@metamask/snaps-controllers 13.1.1 → 14.0.0
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 +12 -1
- package/dist/cronjob/CronjobController.cjs +9 -0
- package/dist/cronjob/CronjobController.cjs.map +1 -1
- package/dist/cronjob/CronjobController.d.cts +16 -1
- package/dist/cronjob/CronjobController.d.cts.map +1 -1
- package/dist/cronjob/CronjobController.d.mts +16 -1
- package/dist/cronjob/CronjobController.d.mts.map +1 -1
- package/dist/cronjob/CronjobController.mjs +9 -0
- package/dist/cronjob/CronjobController.mjs.map +1 -1
- package/dist/multichain/MultichainRouter.cjs +1 -1
- package/dist/multichain/MultichainRouter.cjs.map +1 -1
- package/dist/multichain/MultichainRouter.d.cts +1 -1
- package/dist/multichain/MultichainRouter.d.mts +1 -1
- package/dist/multichain/MultichainRouter.mjs +1 -1
- package/dist/multichain/MultichainRouter.mjs.map +1 -1
- package/dist/snaps/SnapController.cjs +31 -0
- package/dist/snaps/SnapController.cjs.map +1 -1
- package/dist/snaps/SnapController.d.cts +1 -1
- package/dist/snaps/SnapController.d.cts.map +1 -1
- package/dist/snaps/SnapController.d.mts +1 -1
- package/dist/snaps/SnapController.d.mts.map +1 -1
- package/dist/snaps/SnapController.mjs +32 -1
- package/dist/snaps/SnapController.mjs.map +1 -1
- package/dist/snaps/constants.cjs +1 -0
- package/dist/snaps/constants.cjs.map +1 -1
- package/dist/snaps/constants.d.cts.map +1 -1
- package/dist/snaps/constants.d.mts.map +1 -1
- package/dist/snaps/constants.mjs +1 -0
- package/dist/snaps/constants.mjs.map +1 -1
- package/dist/snaps/location/npm.cjs +1 -1
- package/dist/snaps/location/npm.cjs.map +1 -1
- package/dist/snaps/location/npm.mjs +1 -1
- package/dist/snaps/location/npm.mjs.map +1 -1
- package/dist/websocket/WebSocketService.cjs +1 -1
- package/dist/websocket/WebSocketService.cjs.map +1 -1
- package/dist/websocket/WebSocketService.mjs +1 -1
- package/dist/websocket/WebSocketService.mjs.map +1 -1
- package/package.json +8 -12
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [14.0.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING:** Move `CronjobController` init to separate function ([#3507](https://github.com/MetaMask/snaps/pull/3507))
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Add support for `onAssetsMarketData` handler ([#3496](https://github.com/MetaMask/snaps/pull/3496))
|
|
19
|
+
|
|
10
20
|
## [13.1.1]
|
|
11
21
|
|
|
12
22
|
### Fixed
|
|
@@ -826,7 +836,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
826
836
|
- The version of the package no longer needs to match the version of all other
|
|
827
837
|
MetaMask Snaps packages.
|
|
828
838
|
|
|
829
|
-
[Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@
|
|
839
|
+
[Unreleased]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@14.0.0...HEAD
|
|
840
|
+
[14.0.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@13.1.1...@metamask/snaps-controllers@14.0.0
|
|
830
841
|
[13.1.1]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@13.1.0...@metamask/snaps-controllers@13.1.1
|
|
831
842
|
[13.1.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@13.0.0...@metamask/snaps-controllers@13.1.0
|
|
832
843
|
[13.0.0]: https://github.com/MetaMask/snaps/compare/@metamask/snaps-controllers@12.3.1...@metamask/snaps-controllers@13.0.0
|
|
@@ -39,9 +39,18 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
39
39
|
this.messagingSystem.subscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
40
40
|
this.messagingSystem.subscribe('SnapController:snapDisabled', this.#handleSnapDisabledEvent);
|
|
41
41
|
this.messagingSystem.subscribe('SnapController:snapUpdated', this.#handleSnapUpdatedEvent);
|
|
42
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:init`, (...args) => this.init(...args));
|
|
42
43
|
this.messagingSystem.registerActionHandler(`${controllerName}:schedule`, (...args) => this.schedule(...args));
|
|
43
44
|
this.messagingSystem.registerActionHandler(`${controllerName}:cancel`, (...args) => this.cancel(...args));
|
|
44
45
|
this.messagingSystem.registerActionHandler(`${controllerName}:get`, (...args) => this.get(...args));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the CronjobController.
|
|
49
|
+
*
|
|
50
|
+
* This starts the daily timer, clears out expired events
|
|
51
|
+
* and reschedules any remaining events.
|
|
52
|
+
*/
|
|
53
|
+
init() {
|
|
45
54
|
this.#start();
|
|
46
55
|
this.#clear();
|
|
47
56
|
this.#reschedule();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.cjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":";;;AAKA,+DAA2D;AAE3D,mEAGqC;AAGrC,uDAI+B;AAC/B,2CAAmE;AACnE,iCAAkC;AAClC,iCAAiC;AACjC,mCAAgC;AAEhC,uCAA4E;AAS5E,sDAAqD;AACrD,8CAAuC;AAkD1B,QAAA,aAAa,GAAG,IAAA,sBAAc,EAAC,EAAE,EAAE,gBAAQ,CAAC,IAAI,CAAC,CAAC;AAoD/D,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAE3C;;;;GAIG;AACH,MAAa,iBAAkB,SAAQ,gCAItC;IACU,OAAO,CAAqB;IAErC,WAAW,GAAU,IAAI,aAAK,CAAC,qBAAa,CAAC,CAAC;IAE9C,YAAY,EAAE,SAAS,EAAE,KAAK,EAAyB;QACrD,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE;gBACR,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;aAC5C;YACD,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,MAAM,EAAE,EAAE;gBACV,GAAG,KAAK;aACT;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,8BAA8B,EAC9B,IAAI,CAAC,yBAAyB,CAC/B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,gCAAgC,EAChC,IAAI,CAAC,2BAA2B,CACjC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,6BAA6B,EAC7B,IAAI,CAAC,wBAAwB,CAC9B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,SAAS,CAC5B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,WAAW,EAC5B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CACpC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,SAAS,EAC1B,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAClC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,qBAAqB,CACxC,GAAG,cAAc,MAAM,EACvB,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAC/B,CAAC;QAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,KAAoD;QAC3D,OAAO,IAAI,CAAC,IAAI,CAAC;YACf,GAAG,KAAK;YACR,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,MAAc,EAAE,EAAU;QAC/B,IAAA,cAAM,EACJ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EACrB,sCAAsC,EAAE,mBAAmB,CAC5D,CAAC;QAEF,IAAA,cAAM,EACJ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,KAAK,MAAM,EACvC,0DAA0D,CAC3D,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,MAAc;QAChB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;aACpC,MAAM,CACL,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CACnE;aACA,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACf,GAAG,KAAK;YACR,IAAI,EAAE,IAAA,qCAAuB,EAAC,KAAK,CAAC,IAAI,CAAC;YACzC,WAAW,EAAE,IAAA,qCAAuB,EAAC,KAAK,CAAC,WAAW,CAAC;SACxD,CAAC,CAAC,CAAC;IACR,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,MAAc;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAc;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,KAAK,CAAC,OAAO,EAAE,CAAC;QAEhB,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,8BAA8B,EAC9B,IAAI,CAAC,yBAAyB,CAC/B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,gCAAgC,EAChC,IAAI,CAAC,2BAA2B,CACjC,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,6BAA6B,EAC7B,IAAI,CAAC,wBAAwB,CAC9B,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,WAAW,CAC9B,4BAA4B,EAC5B,IAAI,CAAC,uBAAuB,CAC7B,CAAC;QAEF,uCAAuC;QACvC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1C,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAI,CAAC,WAAW,GAAG,IAAI,aAAK,CAAC,qBAAa,CAAC,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,KAAiC;QACpC,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,IAAA,eAAM,GAAE,CAAC;QAChC,MAAM,aAAa,GAA4B;YAC7C,GAAG,KAAK;YACR,EAAE;YACF,IAAI,EAAE,IAAA,wBAAgB,EAAC,KAAK,CAAC,QAAQ,CAAC;YACtC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,IAAA,iBAAS,EAAC,aAAa,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,KAA8B;QACtC,MAAM,IAAI,GAAG,IAAA,wBAAgB,EAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC;YACf,GAAG,KAAK;YACR,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,KAA8B;QACxC,MAAM,EAAE,GACN,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE1E,iEAAiE;QACjE,IAAI,EAAE,GAAG,qBAAa,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,aAAK,CAAC,EAAE,CAAC,CAAC;QAC5B,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;YACf,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACpC,CAAC;IAED;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAA8B;QACrC,IAAI,CAAC,eAAe;aACjB,IAAI,CAAC,8BAA8B,EAAE;YACpC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,2BAAe;YACvB,OAAO,EAAE,yBAAW,CAAC,SAAS;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAA,sBAAQ,EACN,wDAAwD,KAAK,CAAC,MAAM,IAAI,EACxE,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;QAEL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAE9B,uEAAuE;QACvE,oCAAoC;QACpC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;YAEH,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,EAAU;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAExB,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,MAAc;QAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAC3C,qCAAqC,EACrC,MAAM,CACP,CAAC;QAEF,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC,kCAAc,CAAC,OAAO,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,IAAA,wCAAoB,EAAC,UAAU,CAAC,CAAC;QAErD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE;YACzC,OAAO;gBACL,MAAM;gBACN,EAAE,EAAE,WAAW,MAAM,IAAI,GAAG,EAAE;gBAC9B,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,QAAQ,EAAE,IAAA,uCAA+B,EAAC,UAAU,CAAC;gBACrD,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACM,yBAAyB,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC3D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;OAKG;IACM,uBAAuB,GAAG,CAAC,IAAmB,EAAE,EAAE;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;OAKG;IACM,2BAA2B,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC7D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF;;;;;OAKG;IACM,wBAAwB,GAAG,CAAC,IAAmB,EAAE,EAAE;QAC1D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF;;;;OAIG;IACM,uBAAuB,GAAG,CAAC,IAAmB,EAAE,EAAE;QACzD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF;;;;;;;OAOG;IACH,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/B,+DAA+D;gBAC/D,iBAAiB;gBACjB,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC7C,OAAO,EAAE,IAAI;aACd,CAAC;iBACC,KAAK,EAAE;iBACP,QAAQ,EAAE,CAAC;YAEd,oEAAoE;YACpE,eAAe;YACf,IAAI,KAAK,CAAC,SAAS,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;gBACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YAED,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,MAAM,SAAS,GAAG,gBAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE;gBAC7C,OAAO,EAAE,IAAI;aACd,CAAC;iBACC,KAAK,EAAE;iBACP,QAAQ,EAAE,CAAC;YAEd,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;gBACxC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAhcD,8CAgcC","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CronjobController.cjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
@@ -5,6 +5,14 @@ import type { BackgroundEvent, SnapId } from "@metamask/snaps-sdk";
|
|
|
5
5
|
import type { HandleSnapRequest, SnapDisabled, SnapEnabled, SnapInstalled, SnapUninstalled, SnapUpdated } from "../index.cjs";
|
|
6
6
|
export type CronjobControllerGetStateAction = ControllerGetStateAction<typeof controllerName, CronjobControllerState>;
|
|
7
7
|
export type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, CronjobControllerState>;
|
|
8
|
+
/**
|
|
9
|
+
* Initialise the CronjobController. This should be called after all controllers
|
|
10
|
+
* are created.
|
|
11
|
+
*/
|
|
12
|
+
export type CronjobControllerInitAction = {
|
|
13
|
+
type: `${typeof controllerName}:init`;
|
|
14
|
+
handler: CronjobController['init'];
|
|
15
|
+
};
|
|
8
16
|
export type Schedule = {
|
|
9
17
|
type: `${typeof controllerName}:schedule`;
|
|
10
18
|
handler: CronjobController['schedule'];
|
|
@@ -17,7 +25,7 @@ export type Get = {
|
|
|
17
25
|
type: `${typeof controllerName}:get`;
|
|
18
26
|
handler: CronjobController['get'];
|
|
19
27
|
};
|
|
20
|
-
export type CronjobControllerActions = CronjobControllerGetStateAction | HandleSnapRequest | GetPermissions | Schedule | Cancel | Get;
|
|
28
|
+
export type CronjobControllerActions = CronjobControllerGetStateAction | HandleSnapRequest | GetPermissions | Schedule | Cancel | Get | CronjobControllerInitAction;
|
|
21
29
|
export type CronjobControllerEvents = CronjobControllerStateChangeEvent | SnapInstalled | SnapUninstalled | SnapUpdated | SnapEnabled | SnapDisabled;
|
|
22
30
|
export type CronjobControllerMessenger = RestrictedMessenger<typeof controllerName, CronjobControllerActions, CronjobControllerEvents, CronjobControllerActions['type'], CronjobControllerEvents['type']>;
|
|
23
31
|
export declare const DAILY_TIMEOUT: number;
|
|
@@ -71,6 +79,13 @@ declare const controllerName = "CronjobController";
|
|
|
71
79
|
export declare class CronjobController extends BaseController<typeof controllerName, CronjobControllerState, CronjobControllerMessenger> {
|
|
72
80
|
#private;
|
|
73
81
|
constructor({ messenger, state }: CronjobControllerArgs);
|
|
82
|
+
/**
|
|
83
|
+
* Initialize the CronjobController.
|
|
84
|
+
*
|
|
85
|
+
* This starts the daily timer, clears out expired events
|
|
86
|
+
* and reschedules any remaining events.
|
|
87
|
+
*/
|
|
88
|
+
init(): void;
|
|
74
89
|
/**
|
|
75
90
|
* Schedule a non-recurring background event.
|
|
76
91
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.d.cts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,wCAAwC;AAKtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,4BAA4B;AAanE,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACZ,qBAAW;AAIZ,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CACpE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AACF,MAAM,MAAM,iCAAiC,GAAG,0BAA0B,CACxE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,GAAG,OAAO,cAAc,WAAW,CAAC;IAC1C,OAAO,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,GAAG,OAAO,cAAc,SAAS,CAAC;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,GAAG,OAAO,cAAc,MAAM,CAAC;IACrC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,iBAAiB,GACjB,cAAc,GACd,QAAQ,GACR,MAAM,GACN,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"CronjobController.d.cts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,14 @@ import type { BackgroundEvent, SnapId } from "@metamask/snaps-sdk";
|
|
|
5
5
|
import type { HandleSnapRequest, SnapDisabled, SnapEnabled, SnapInstalled, SnapUninstalled, SnapUpdated } from "../index.mjs";
|
|
6
6
|
export type CronjobControllerGetStateAction = ControllerGetStateAction<typeof controllerName, CronjobControllerState>;
|
|
7
7
|
export type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, CronjobControllerState>;
|
|
8
|
+
/**
|
|
9
|
+
* Initialise the CronjobController. This should be called after all controllers
|
|
10
|
+
* are created.
|
|
11
|
+
*/
|
|
12
|
+
export type CronjobControllerInitAction = {
|
|
13
|
+
type: `${typeof controllerName}:init`;
|
|
14
|
+
handler: CronjobController['init'];
|
|
15
|
+
};
|
|
8
16
|
export type Schedule = {
|
|
9
17
|
type: `${typeof controllerName}:schedule`;
|
|
10
18
|
handler: CronjobController['schedule'];
|
|
@@ -17,7 +25,7 @@ export type Get = {
|
|
|
17
25
|
type: `${typeof controllerName}:get`;
|
|
18
26
|
handler: CronjobController['get'];
|
|
19
27
|
};
|
|
20
|
-
export type CronjobControllerActions = CronjobControllerGetStateAction | HandleSnapRequest | GetPermissions | Schedule | Cancel | Get;
|
|
28
|
+
export type CronjobControllerActions = CronjobControllerGetStateAction | HandleSnapRequest | GetPermissions | Schedule | Cancel | Get | CronjobControllerInitAction;
|
|
21
29
|
export type CronjobControllerEvents = CronjobControllerStateChangeEvent | SnapInstalled | SnapUninstalled | SnapUpdated | SnapEnabled | SnapDisabled;
|
|
22
30
|
export type CronjobControllerMessenger = RestrictedMessenger<typeof controllerName, CronjobControllerActions, CronjobControllerEvents, CronjobControllerActions['type'], CronjobControllerEvents['type']>;
|
|
23
31
|
export declare const DAILY_TIMEOUT: number;
|
|
@@ -71,6 +79,13 @@ declare const controllerName = "CronjobController";
|
|
|
71
79
|
export declare class CronjobController extends BaseController<typeof controllerName, CronjobControllerState, CronjobControllerMessenger> {
|
|
72
80
|
#private;
|
|
73
81
|
constructor({ messenger, state }: CronjobControllerArgs);
|
|
82
|
+
/**
|
|
83
|
+
* Initialize the CronjobController.
|
|
84
|
+
*
|
|
85
|
+
* This starts the daily timer, clears out expired events
|
|
86
|
+
* and reschedules any remaining events.
|
|
87
|
+
*/
|
|
88
|
+
init(): void;
|
|
74
89
|
/**
|
|
75
90
|
* Schedule a non-recurring background event.
|
|
76
91
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.d.mts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,wCAAwC;AAKtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,4BAA4B;AAanE,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,WAAW,EACZ,qBAAW;AAIZ,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CACpE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AACF,MAAM,MAAM,iCAAiC,GAAG,0BAA0B,CACxE,OAAO,cAAc,EACrB,sBAAsB,CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,GAAG,OAAO,cAAc,WAAW,CAAC;IAC1C,OAAO,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,GAAG,OAAO,cAAc,SAAS,CAAC;IACxC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG;IAChB,IAAI,EAAE,GAAG,OAAO,cAAc,MAAM,CAAC;IACrC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC,+BAA+B,GAC/B,iBAAiB,GACjB,cAAc,GACd,QAAQ,GACR,MAAM,GACN,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"CronjobController.d.mts","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,9 +36,18 @@ export class CronjobController extends BaseController {
|
|
|
36
36
|
this.messagingSystem.subscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
37
37
|
this.messagingSystem.subscribe('SnapController:snapDisabled', this.#handleSnapDisabledEvent);
|
|
38
38
|
this.messagingSystem.subscribe('SnapController:snapUpdated', this.#handleSnapUpdatedEvent);
|
|
39
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:init`, (...args) => this.init(...args));
|
|
39
40
|
this.messagingSystem.registerActionHandler(`${controllerName}:schedule`, (...args) => this.schedule(...args));
|
|
40
41
|
this.messagingSystem.registerActionHandler(`${controllerName}:cancel`, (...args) => this.cancel(...args));
|
|
41
42
|
this.messagingSystem.registerActionHandler(`${controllerName}:get`, (...args) => this.get(...args));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Initialize the CronjobController.
|
|
46
|
+
*
|
|
47
|
+
* This starts the daily timer, clears out expired events
|
|
48
|
+
* and reschedules any remaining events.
|
|
49
|
+
*/
|
|
50
|
+
init() {
|
|
42
51
|
this.#start();
|
|
43
52
|
this.#clear();
|
|
44
53
|
this.#reschedule();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronjobController.mjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CronjobController.mjs","sourceRoot":"","sources":["../../src/cronjob/CronjobController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RestrictedMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport {\n getCronjobCaveatJobs,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { BackgroundEvent, SnapId } from '@metamask/snaps-sdk';\nimport type { TruncatedSnap } from '@metamask/snaps-utils';\nimport {\n toCensoredISO8601String,\n HandlerType,\n logError,\n} from '@metamask/snaps-utils';\nimport { assert, Duration, inMilliseconds } from '@metamask/utils';\nimport { castDraft } from 'immer';\nimport { DateTime } from 'luxon';\nimport { nanoid } from 'nanoid';\n\nimport { getCronjobSpecificationSchedule, getExecutionDate } from './utils';\nimport type {\n HandleSnapRequest,\n SnapDisabled,\n SnapEnabled,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '..';\nimport { METAMASK_ORIGIN } from '../snaps/constants';\nimport { Timer } from '../snaps/Timer';\n\nexport type CronjobControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n CronjobControllerState\n>;\nexport type CronjobControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n CronjobControllerState\n>;\n\n/**\n * Initialise the CronjobController. This should be called after all controllers\n * are created.\n */\nexport type CronjobControllerInitAction = {\n type: `${typeof controllerName}:init`;\n handler: CronjobController['init'];\n};\n\nexport type Schedule = {\n type: `${typeof controllerName}:schedule`;\n handler: CronjobController['schedule'];\n};\n\nexport type Cancel = {\n type: `${typeof controllerName}:cancel`;\n handler: CronjobController['cancel'];\n};\n\nexport type Get = {\n type: `${typeof controllerName}:get`;\n handler: CronjobController['get'];\n};\n\nexport type CronjobControllerActions =\n | CronjobControllerGetStateAction\n | HandleSnapRequest\n | GetPermissions\n | Schedule\n | Cancel\n | Get\n | CronjobControllerInitAction;\n\nexport type CronjobControllerEvents =\n | CronjobControllerStateChangeEvent\n | SnapInstalled\n | SnapUninstalled\n | SnapUpdated\n | SnapEnabled\n | SnapDisabled;\n\nexport type CronjobControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n CronjobControllerActions,\n CronjobControllerEvents,\n CronjobControllerActions['type'],\n CronjobControllerEvents['type']\n>;\n\nexport const DAILY_TIMEOUT = inMilliseconds(24, Duration.Hour);\n\nexport type CronjobControllerArgs = {\n messenger: CronjobControllerMessenger;\n\n /**\n * Persisted state that will be used for rehydration.\n */\n state?: CronjobControllerState;\n};\n\n/**\n * Represents a background event that is scheduled to be executed by the\n * cronjob controller.\n */\nexport type InternalBackgroundEvent = BackgroundEvent & {\n /**\n * Whether the event is recurring.\n */\n recurring: boolean;\n\n /**\n * The cron expression or ISO 8601 duration string that defines the event's\n * schedule.\n */\n schedule: string;\n};\n\n/**\n * A schedulable background event, which is a subset of the\n * {@link InternalBackgroundEvent} type, containing only the fields required to\n * schedule an event. Other fields will be populated by the cronjob controller\n * automatically.\n */\nexport type SchedulableBackgroundEvent = Omit<\n InternalBackgroundEvent,\n 'scheduledAt' | 'date' | 'id'\n> & {\n /**\n * The optional ID of the event. If not provided, a new ID will be\n * generated.\n */\n id?: string;\n};\n\nexport type CronjobControllerState = {\n /**\n * Background events and cronjobs that are scheduled to be executed.\n */\n events: Record<string, InternalBackgroundEvent>;\n};\n\nconst controllerName = 'CronjobController';\n\n/**\n * The cronjob controller is responsible for managing cronjobs and background\n * events for Snaps. It allows Snaps to schedule events that will be executed\n * at a later time.\n */\nexport class CronjobController extends BaseController<\n typeof controllerName,\n CronjobControllerState,\n CronjobControllerMessenger\n> {\n readonly #timers: Map<string, Timer>;\n\n #dailyTimer: Timer = new Timer(DAILY_TIMEOUT);\n\n constructor({ messenger, state }: CronjobControllerArgs) {\n super({\n messenger,\n metadata: {\n events: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n events: {},\n ...state,\n },\n });\n\n this.#timers = new Map();\n\n this.messagingSystem.subscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.subscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:init`,\n (...args) => this.init(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:schedule`,\n (...args) => this.schedule(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:cancel`,\n (...args) => this.cancel(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:get`,\n (...args) => this.get(...args),\n );\n }\n\n /**\n * Initialize the CronjobController.\n *\n * This starts the daily timer, clears out expired events\n * and reschedules any remaining events.\n */\n init() {\n this.#start();\n this.#clear();\n this.#reschedule();\n }\n\n /**\n * Schedule a non-recurring background event.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n schedule(event: Omit<SchedulableBackgroundEvent, 'recurring'>) {\n return this.#add({\n ...event,\n recurring: false,\n });\n }\n\n /**\n * Cancel an event.\n *\n * @param origin - The origin making the cancel call.\n * @param id - The id of the event to cancel.\n * @throws If the event does not exist.\n */\n cancel(origin: string, id: string) {\n assert(\n this.state.events[id],\n `A background event with the id of \"${id}\" does not exist.`,\n );\n\n assert(\n this.state.events[id].snapId === origin,\n 'Only the origin that scheduled this event can cancel it.',\n );\n\n this.#cancel(id);\n }\n\n /**\n * Get a list of a Snap's background events.\n *\n * @param snapId - The id of the Snap to fetch background events for.\n * @returns An array of background events.\n */\n get(snapId: SnapId): InternalBackgroundEvent[] {\n return Object.values(this.state.events)\n .filter(\n (snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring,\n )\n .map((event) => ({\n ...event,\n date: toCensoredISO8601String(event.date),\n scheduledAt: toCensoredISO8601String(event.scheduledAt),\n }));\n }\n\n /**\n * Register cronjobs for a given Snap by getting specification from the\n * permission caveats. Once registered, each job will be scheduled.\n *\n * @param snapId - The snap ID to register jobs for.\n */\n register(snapId: SnapId) {\n const jobs = this.#getSnapCronjobs(snapId);\n jobs?.forEach((job) => this.#add(job));\n }\n\n /**\n * Unregister all cronjobs and background events for a given Snap.\n *\n * @param snapId - ID of a snap.\n */\n unregister(snapId: SnapId) {\n for (const [id, event] of Object.entries(this.state.events)) {\n if (event.snapId === snapId) {\n this.#cancel(id);\n }\n }\n }\n\n /**\n * Run controller teardown process and unsubscribe from Snap events.\n */\n destroy() {\n super.destroy();\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapInstalled',\n this.#handleSnapInstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUninstalled',\n this.#handleSnapUninstalledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapEnabled',\n this.#handleSnapEnabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapDisabled',\n this.#handleSnapDisabledEvent,\n );\n\n this.messagingSystem.unsubscribe(\n 'SnapController:snapUpdated',\n this.#handleSnapUpdatedEvent,\n );\n\n // Cancel all timers and clear the map.\n this.#timers.forEach((timer) => timer.cancel());\n this.#timers.clear();\n\n if (this.#dailyTimer.status === 'running') {\n this.#dailyTimer.cancel();\n }\n }\n\n /**\n * Start the daily timer that will reschedule events every 24 hours.\n */\n #start() {\n this.#dailyTimer = new Timer(DAILY_TIMEOUT);\n this.#dailyTimer.start(() => {\n this.#reschedule();\n this.#start();\n });\n }\n\n /**\n * Add a cronjob or background event to the controller state and schedule it\n * for execution.\n *\n * @param event - The event to schedule.\n * @returns The ID of the scheduled event.\n */\n #add(event: SchedulableBackgroundEvent) {\n const id = event.id ?? nanoid();\n const internalEvent: InternalBackgroundEvent = {\n ...event,\n id,\n date: getExecutionDate(event.schedule),\n scheduledAt: new Date().toISOString(),\n };\n\n this.update((state) => {\n state.events[internalEvent.id] = castDraft(internalEvent);\n });\n\n this.#schedule(internalEvent);\n return id;\n }\n\n /**\n * Get the next execution date for a given event and start a timer for it.\n *\n * @param event - The event to schedule.\n */\n #schedule(event: InternalBackgroundEvent) {\n const date = getExecutionDate(event.schedule);\n this.update((state) => {\n state.events[event.id].date = date;\n });\n\n this.#startTimer({\n ...event,\n date,\n });\n }\n\n /**\n * Set up and start a timer for the given event.\n *\n * @param event - The event to schedule.\n * @throws If the event is scheduled in the past.\n */\n #startTimer(event: InternalBackgroundEvent) {\n const ms =\n DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();\n\n // We don't schedule this job yet as it is too far in the future.\n if (ms > DAILY_TIMEOUT) {\n return;\n }\n\n const timer = new Timer(ms);\n timer.start(() => {\n this.#execute(event);\n });\n\n this.#timers.set(event.id, timer);\n }\n\n /**\n * Execute a background event. This method is called when the event's timer\n * expires.\n *\n * If the event is not recurring, it will be removed from the state after\n * execution. If it is recurring, it will be rescheduled.\n *\n * @param event - The event to execute.\n */\n #execute(event: InternalBackgroundEvent) {\n this.messagingSystem\n .call('SnapController:handleRequest', {\n snapId: event.snapId,\n origin: METAMASK_ORIGIN,\n handler: HandlerType.OnCronjob,\n request: event.request,\n })\n .catch((error) => {\n logError(\n `An error occurred while executing an event for Snap \"${event.snapId}\":`,\n error,\n );\n });\n\n this.#timers.delete(event.id);\n\n // Non-recurring events are removed from the state after execution, and\n // recurring events are rescheduled.\n if (!event.recurring) {\n this.update((state) => {\n delete state.events[event.id];\n });\n\n return;\n }\n\n this.#schedule(event);\n }\n\n /**\n * Cancel a background event by its ID. Unlike {@link cancel}, this method\n * does not check the origin of the event, so it can be used internally.\n *\n * @param id - The ID of the background event to cancel.\n */\n #cancel(id: string) {\n const timer = this.#timers.get(id);\n timer?.cancel();\n this.#timers.delete(id);\n\n this.update((state) => {\n delete state.events[id];\n });\n }\n\n /**\n * Retrieve all cronjob specifications for a Snap.\n *\n * @param snapId - ID of a Snap.\n * @returns Array of cronjob specifications.\n */\n #getSnapCronjobs(snapId: SnapId): SchedulableBackgroundEvent[] {\n const permissions = this.messagingSystem.call(\n 'PermissionController:getPermissions',\n snapId,\n );\n\n const permission = permissions?.[SnapEndowments.Cronjob];\n const definitions = getCronjobCaveatJobs(permission);\n\n if (!definitions) {\n return [];\n }\n\n return definitions.map((definition, idx) => {\n return {\n snapId,\n id: `cronjob-${snapId}-${idx}`,\n request: definition.request,\n schedule: getCronjobSpecificationSchedule(definition),\n recurring: true,\n };\n });\n }\n\n /**\n * Handle events that should cause cron jobs to be registered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapInstalledEvent = (snap: TruncatedSnap) => {\n this.register(snap.id);\n };\n\n /**\n * Handle the Snap enabled event. This checks if the Snap has any cronjobs or\n * background events that need to be rescheduled.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapEnabledEvent = (snap: TruncatedSnap) => {\n const events = this.get(snap.id);\n this.#reschedule(events);\n this.register(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUninstalledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle events that should cause cronjobs and background events to be\n * unregistered.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapDisabledEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n };\n\n /**\n * Handle cron jobs on 'snapUpdated' event.\n *\n * @param snap - Basic Snap information.\n */\n readonly #handleSnapUpdatedEvent = (snap: TruncatedSnap) => {\n this.unregister(snap.id);\n this.register(snap.id);\n };\n\n /**\n * Reschedule events that are yet to be executed. This should be called on\n * controller initialization and once every 24 hours to ensure that\n * background events are scheduled correctly.\n *\n * @param events - An array of events to reschedule. Defaults to all events in\n * the controller state.\n */\n #reschedule(events = Object.values(this.state.events)) {\n const now = Date.now();\n\n for (const event of events) {\n if (this.#timers.has(event.id)) {\n // If the timer for this event already exists, we don't need to\n // reschedule it.\n continue;\n }\n\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n // If the event is recurring and the date is in the past, execute it\n // immediately.\n if (event.recurring && eventDate <= now) {\n this.#execute(event);\n }\n\n this.#schedule(event);\n }\n }\n\n /**\n * Clear non-recurring events that are past their scheduled time.\n */\n #clear() {\n const now = Date.now();\n\n for (const event of Object.values(this.state.events)) {\n const eventDate = DateTime.fromISO(event.date, {\n setZone: true,\n })\n .toUTC()\n .toMillis();\n\n if (!event.recurring && eventDate < now) {\n this.#cancel(event.id);\n }\n }\n }\n}\n"]}
|
|
@@ -110,7 +110,7 @@ class MultichainRouter {
|
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
112
|
* Handle an incoming JSON-RPC request tied to a specific scope by routing
|
|
113
|
-
* to either a
|
|
113
|
+
* to either a protocol Snap or an account Snap.
|
|
114
114
|
*
|
|
115
115
|
* Note: Addresses are considered case sensitive by the MultichainRouter as
|
|
116
116
|
* not all non-EVM chains are case insensitive.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainRouter.cjs","sourceRoot":"","sources":["../../src/multichain/MultichainRouter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedMessenger } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n getProtocolCaveatScopes,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport type { InternalAccount } from '@metamask/snaps-utils';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type {\n CaipAccountId,\n CaipChainId,\n JsonRpcParams,\n} from '@metamask/utils';\nimport {\n assert,\n hasProperty,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport { nanoid } from 'nanoid';\n\nimport { getRunnableSnaps } from '../snaps';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\n\nexport type MultichainRouterHandleRequestAction = {\n type: `${typeof name}:handleRequest`;\n handler: MultichainRouter['handleRequest'];\n};\n\nexport type MultichainRouterGetSupportedMethodsAction = {\n type: `${typeof name}:getSupportedMethods`;\n handler: MultichainRouter['getSupportedMethods'];\n};\n\nexport type MultichainRouterGetSupportedAccountsAction = {\n type: `${typeof name}:getSupportedAccounts`;\n handler: MultichainRouter['getSupportedAccounts'];\n};\n\nexport type MultichainRouterIsSupportedScopeAction = {\n type: `${typeof name}:isSupportedScope`;\n handler: MultichainRouter['isSupportedScope'];\n};\n\ntype SnapKeyring = {\n submitRequest: (request: {\n origin: string;\n account: string;\n method: string;\n params?: Json[] | Record<string, Json>;\n scope: CaipChainId;\n }) => Promise<Json>;\n resolveAccountAddress: (\n snapId: SnapId,\n scope: CaipChainId,\n request: Json,\n ) => Promise<{ address: CaipAccountId } | null>;\n};\n\n// Expecting a bound function that calls KeyringController.withKeyring selecting the Snap keyring\ntype WithSnapKeyringFunction = <ReturnType>(\n operation: ({ keyring }: { keyring: SnapKeyring }) => Promise<ReturnType>,\n) => Promise<ReturnType>;\n\nexport type AccountsControllerListMultichainAccountsAction = {\n type: `AccountsController:listMultichainAccounts`;\n handler: (chainId?: CaipChainId) => InternalAccount[];\n};\n\nexport type MultichainRouterActions =\n | MultichainRouterHandleRequestAction\n | MultichainRouterGetSupportedMethodsAction\n | MultichainRouterGetSupportedAccountsAction\n | MultichainRouterIsSupportedScopeAction;\n\nexport type MultichainRouterAllowedActions =\n | GetAllSnaps\n | HandleSnapRequest\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction;\n\nexport type MultichainRouterEvents = never;\n\nexport type MultichainRouterMessenger = RestrictedMessenger<\n typeof name,\n MultichainRouterActions | MultichainRouterAllowedActions,\n never,\n MultichainRouterAllowedActions['type'],\n MultichainRouterEvents['type']\n>;\n\nexport type MultichainRouterArgs = {\n messenger: MultichainRouterMessenger;\n withSnapKeyring: WithSnapKeyringFunction;\n};\n\ntype ProtocolSnap = {\n snapId: SnapId;\n methods: string[];\n};\n\nconst name = 'MultichainRouter';\n\nexport class MultichainRouter {\n name: typeof name = name;\n\n state = null;\n\n readonly #messenger: MultichainRouterMessenger;\n\n readonly #withSnapKeyring: WithSnapKeyringFunction;\n\n constructor({ messenger, withSnapKeyring }: MultichainRouterArgs) {\n this.#messenger = messenger;\n this.#withSnapKeyring = withSnapKeyring;\n\n this.#messenger.registerActionHandler(\n `${name}:handleRequest`,\n async (...args) => this.handleRequest(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedMethods`,\n (...args) => this.getSupportedMethods(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedAccounts`,\n (...args) => this.getSupportedAccounts(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:isSupportedScope`,\n (...args) => this.isSupportedScope(...args),\n );\n }\n\n /**\n * Attempts to resolve the account address to use for a given request by inspecting the request itself.\n *\n * The request is sent to to an account Snap via the SnapKeyring that will attempt this resolution.\n *\n * @param snapId - The ID of the Snap to send the request to.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns The resolved address if found, otherwise null.\n * @throws If the invocation of the SnapKeyring fails.\n */\n async #resolveRequestAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n try {\n const result = await this.#withSnapKeyring(async ({ keyring }) =>\n keyring.resolveAccountAddress(snapId, scope, request),\n );\n const address = result?.address;\n return address ? parseCaipAccountId(address).address : null;\n } catch {\n throw rpcErrors.internal();\n }\n }\n\n /**\n * Get the account ID of the account that should service the RPC request via an account Snap.\n *\n * This function checks whether any accounts exist that can service a given request by\n * using a combination of the resolveAccountAddress functionality and the connected accounts.\n *\n * If an account is expected to service this request but none is found, the function will throw.\n *\n * @param connectedAddresses - The CAIP-10 addresses connected to the requesting origin.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns An account ID if found, otherwise null.\n * @throws If no account is found, but the accounts exist that could service the request.\n */\n async #getSnapAccountId(\n connectedAddresses: CaipAccountId[],\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n const accounts = this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter(\n (\n account: InternalAccount,\n ): account is InternalAccount & {\n metadata: Required<InternalAccount['metadata']>;\n } =>\n Boolean(account.metadata.snap?.enabled) &&\n account.methods.includes(request.method),\n );\n\n // If no accounts can service the request, return null.\n if (accounts.length === 0) {\n return null;\n }\n\n const resolutionSnapId = accounts[0].metadata.snap.id;\n\n // Attempt to resolve the address that should be used for signing.\n const address = await this.#resolveRequestAddress(\n resolutionSnapId,\n scope,\n request,\n );\n\n const parsedConnectedAddresses = connectedAddresses.map(\n (connectedAddress) => parseCaipAccountId(connectedAddress).address,\n );\n\n // If we have a resolved address, try to find the selected account based on that\n // otherwise, default to one of the connected accounts.\n // TODO: Eventually let the user choose if we have more than one option for the account.\n const selectedAccount = accounts.find(\n (account) =>\n parsedConnectedAddresses.includes(account.address) &&\n (!address || account.address === address),\n );\n\n if (!selectedAccount) {\n throw rpcErrors.invalidParams({\n message: 'No available account found for request.',\n });\n }\n\n return selectedAccount.id;\n }\n\n /**\n * Get all protocol Snaps that can service a given CAIP-2 scope.\n *\n * Protocol Snaps are deemed fit to service a scope if they are runnable\n * and have the proper permissions set for the scope.\n *\n * @param scope - A CAIP-2 scope.\n * @returns A list of all the protocol Snaps available and their RPC methods.\n */\n #getProtocolSnaps(scope: CaipChainId) {\n const allSnaps = this.#messenger.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<ProtocolSnap[]>((accumulator, snap) => {\n const permissions = this.#messenger.call(\n 'PermissionController:getPermissions',\n snap.id,\n );\n\n if (permissions && hasProperty(permissions, SnapEndowments.Protocol)) {\n const permission = permissions[SnapEndowments.Protocol];\n const scopes = getProtocolCaveatScopes(permission);\n if (scopes && hasProperty(scopes, scope)) {\n accumulator.push({\n snapId: snap.id,\n methods: scopes[scope].methods,\n });\n }\n }\n\n return accumulator;\n }, []);\n }\n\n /**\n * Handle an incoming JSON-RPC request tied to a specific scope by routing\n * to either a procotol Snap or an account Snap.\n *\n * Note: Addresses are considered case sensitive by the MultichainRouter as\n * not all non-EVM chains are case insensitive.\n *\n * @param options - An options bag.\n * @param options.connectedAddresses - Addresses currently connected to the origin.\n * @param options.origin - The origin of the RPC request.\n * @param options.request - The JSON-RPC request.\n * @param options.scope - The CAIP-2 scope for the request.\n * @returns The response from the chosen Snap.\n * @throws If no handler was found.\n */\n async handleRequest({\n connectedAddresses,\n origin,\n scope,\n request: rawRequest,\n }: {\n connectedAddresses: CaipAccountId[];\n origin: string;\n scope: CaipChainId;\n request: JsonRpcRequest;\n }): Promise<Json> {\n // Explicitly block EVM scopes, just in case.\n assert(\n !scope.startsWith(KnownCaipNamespace.Eip155) &&\n !scope.startsWith('wallet:eip155'),\n );\n\n // Re-create the request to simplify and remove additional properties that may be present in MM middleware.\n const request = {\n jsonrpc: '2.0' as const,\n id: rawRequest.id ?? nanoid(),\n method: rawRequest.method,\n ...(rawRequest.params ? { params: rawRequest.params } : {}),\n };\n\n const { method, params } = request;\n\n // If the RPC request can be serviced by an account Snap, route it there.\n const accountId = await this.#getSnapAccountId(\n connectedAddresses,\n scope,\n request,\n );\n\n if (accountId) {\n return this.#withSnapKeyring(async ({ keyring }) =>\n keyring.submitRequest({\n origin,\n account: accountId,\n scope,\n method,\n params: params as JsonRpcParams,\n }),\n );\n }\n\n // If the RPC request cannot be serviced by an account Snap,\n // but has a protocol Snap available, route it there.\n const protocolSnaps = this.#getProtocolSnaps(scope);\n const protocolSnap = protocolSnaps.find((snap) =>\n snap.methods.includes(method),\n );\n\n if (protocolSnap) {\n return this.#messenger.call('SnapController:handleRequest', {\n snapId: protocolSnap.snapId,\n origin,\n request: {\n method: '',\n params: {\n request,\n scope,\n },\n },\n handler: HandlerType.OnProtocolRequest,\n }) as Promise<Json>;\n }\n\n // If no compatible account or protocol Snaps were found, throw.\n throw rpcErrors.methodNotFound();\n }\n\n /**\n * Get a list of metadata for supported accounts for a given scope from the client.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of metadata for the supported accounts.\n */\n #getSupportedAccountsMetadata(scope: CaipChainId): InternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter((account: InternalAccount) => account.metadata.snap?.enabled);\n }\n\n /**\n * Get a list of supported methods for a given scope.\n * This combines both protocol and account Snaps supported methods.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of supported methods.\n */\n getSupportedMethods(scope: CaipChainId): string[] {\n const accountMethods = this.#getSupportedAccountsMetadata(scope).flatMap(\n (account) => account.methods,\n );\n\n const protocolMethods = this.#getProtocolSnaps(scope).flatMap(\n (snap) => snap.methods,\n );\n\n return Array.from(new Set([...accountMethods, ...protocolMethods]));\n }\n\n /**\n * Get a list of supported accounts for a given scope.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of CAIP-10 addresses.\n */\n getSupportedAccounts(scope: CaipChainId): string[] {\n return this.#getSupportedAccountsMetadata(scope).map(\n (account) => `${scope}:${account.address}`,\n );\n }\n\n /**\n * Determine whether a given CAIP-2 scope is supported by the router.\n *\n * @param scope - The CAIP-2 scope.\n * @returns True if the router can service the scope, otherwise false.\n */\n isSupportedScope(scope: CaipChainId): boolean {\n const hasAccountSnap = this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .some((account: InternalAccount) => account.metadata.snap?.enabled);\n // We currently assume here that if one Snap exists that service the scope, we can service the scope generally.\n return hasAccountSnap || this.#getProtocolSnaps(scope).length > 0;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainRouter.cjs","sourceRoot":"","sources":["../../src/multichain/MultichainRouter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedMessenger } from '@metamask/base-controller';\nimport type { GetPermissions } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n getProtocolCaveatScopes,\n SnapEndowments,\n} from '@metamask/snaps-rpc-methods';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport type { InternalAccount } from '@metamask/snaps-utils';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport type {\n CaipAccountId,\n CaipChainId,\n JsonRpcParams,\n} from '@metamask/utils';\nimport {\n assert,\n hasProperty,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\nimport { nanoid } from 'nanoid';\n\nimport { getRunnableSnaps } from '../snaps';\nimport type { GetAllSnaps, HandleSnapRequest } from '../snaps';\n\nexport type MultichainRouterHandleRequestAction = {\n type: `${typeof name}:handleRequest`;\n handler: MultichainRouter['handleRequest'];\n};\n\nexport type MultichainRouterGetSupportedMethodsAction = {\n type: `${typeof name}:getSupportedMethods`;\n handler: MultichainRouter['getSupportedMethods'];\n};\n\nexport type MultichainRouterGetSupportedAccountsAction = {\n type: `${typeof name}:getSupportedAccounts`;\n handler: MultichainRouter['getSupportedAccounts'];\n};\n\nexport type MultichainRouterIsSupportedScopeAction = {\n type: `${typeof name}:isSupportedScope`;\n handler: MultichainRouter['isSupportedScope'];\n};\n\ntype SnapKeyring = {\n submitRequest: (request: {\n origin: string;\n account: string;\n method: string;\n params?: Json[] | Record<string, Json>;\n scope: CaipChainId;\n }) => Promise<Json>;\n resolveAccountAddress: (\n snapId: SnapId,\n scope: CaipChainId,\n request: Json,\n ) => Promise<{ address: CaipAccountId } | null>;\n};\n\n// Expecting a bound function that calls KeyringController.withKeyring selecting the Snap keyring\ntype WithSnapKeyringFunction = <ReturnType>(\n operation: ({ keyring }: { keyring: SnapKeyring }) => Promise<ReturnType>,\n) => Promise<ReturnType>;\n\nexport type AccountsControllerListMultichainAccountsAction = {\n type: `AccountsController:listMultichainAccounts`;\n handler: (chainId?: CaipChainId) => InternalAccount[];\n};\n\nexport type MultichainRouterActions =\n | MultichainRouterHandleRequestAction\n | MultichainRouterGetSupportedMethodsAction\n | MultichainRouterGetSupportedAccountsAction\n | MultichainRouterIsSupportedScopeAction;\n\nexport type MultichainRouterAllowedActions =\n | GetAllSnaps\n | HandleSnapRequest\n | GetPermissions\n | AccountsControllerListMultichainAccountsAction;\n\nexport type MultichainRouterEvents = never;\n\nexport type MultichainRouterMessenger = RestrictedMessenger<\n typeof name,\n MultichainRouterActions | MultichainRouterAllowedActions,\n never,\n MultichainRouterAllowedActions['type'],\n MultichainRouterEvents['type']\n>;\n\nexport type MultichainRouterArgs = {\n messenger: MultichainRouterMessenger;\n withSnapKeyring: WithSnapKeyringFunction;\n};\n\ntype ProtocolSnap = {\n snapId: SnapId;\n methods: string[];\n};\n\nconst name = 'MultichainRouter';\n\nexport class MultichainRouter {\n name: typeof name = name;\n\n state = null;\n\n readonly #messenger: MultichainRouterMessenger;\n\n readonly #withSnapKeyring: WithSnapKeyringFunction;\n\n constructor({ messenger, withSnapKeyring }: MultichainRouterArgs) {\n this.#messenger = messenger;\n this.#withSnapKeyring = withSnapKeyring;\n\n this.#messenger.registerActionHandler(\n `${name}:handleRequest`,\n async (...args) => this.handleRequest(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedMethods`,\n (...args) => this.getSupportedMethods(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:getSupportedAccounts`,\n (...args) => this.getSupportedAccounts(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${name}:isSupportedScope`,\n (...args) => this.isSupportedScope(...args),\n );\n }\n\n /**\n * Attempts to resolve the account address to use for a given request by inspecting the request itself.\n *\n * The request is sent to to an account Snap via the SnapKeyring that will attempt this resolution.\n *\n * @param snapId - The ID of the Snap to send the request to.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns The resolved address if found, otherwise null.\n * @throws If the invocation of the SnapKeyring fails.\n */\n async #resolveRequestAddress(\n snapId: SnapId,\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n try {\n const result = await this.#withSnapKeyring(async ({ keyring }) =>\n keyring.resolveAccountAddress(snapId, scope, request),\n );\n const address = result?.address;\n return address ? parseCaipAccountId(address).address : null;\n } catch {\n throw rpcErrors.internal();\n }\n }\n\n /**\n * Get the account ID of the account that should service the RPC request via an account Snap.\n *\n * This function checks whether any accounts exist that can service a given request by\n * using a combination of the resolveAccountAddress functionality and the connected accounts.\n *\n * If an account is expected to service this request but none is found, the function will throw.\n *\n * @param connectedAddresses - The CAIP-10 addresses connected to the requesting origin.\n * @param scope - The CAIP-2 scope for the request.\n * @param request - The JSON-RPC request.\n * @returns An account ID if found, otherwise null.\n * @throws If no account is found, but the accounts exist that could service the request.\n */\n async #getSnapAccountId(\n connectedAddresses: CaipAccountId[],\n scope: CaipChainId,\n request: JsonRpcRequest,\n ) {\n const accounts = this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter(\n (\n account: InternalAccount,\n ): account is InternalAccount & {\n metadata: Required<InternalAccount['metadata']>;\n } =>\n Boolean(account.metadata.snap?.enabled) &&\n account.methods.includes(request.method),\n );\n\n // If no accounts can service the request, return null.\n if (accounts.length === 0) {\n return null;\n }\n\n const resolutionSnapId = accounts[0].metadata.snap.id;\n\n // Attempt to resolve the address that should be used for signing.\n const address = await this.#resolveRequestAddress(\n resolutionSnapId,\n scope,\n request,\n );\n\n const parsedConnectedAddresses = connectedAddresses.map(\n (connectedAddress) => parseCaipAccountId(connectedAddress).address,\n );\n\n // If we have a resolved address, try to find the selected account based on that\n // otherwise, default to one of the connected accounts.\n // TODO: Eventually let the user choose if we have more than one option for the account.\n const selectedAccount = accounts.find(\n (account) =>\n parsedConnectedAddresses.includes(account.address) &&\n (!address || account.address === address),\n );\n\n if (!selectedAccount) {\n throw rpcErrors.invalidParams({\n message: 'No available account found for request.',\n });\n }\n\n return selectedAccount.id;\n }\n\n /**\n * Get all protocol Snaps that can service a given CAIP-2 scope.\n *\n * Protocol Snaps are deemed fit to service a scope if they are runnable\n * and have the proper permissions set for the scope.\n *\n * @param scope - A CAIP-2 scope.\n * @returns A list of all the protocol Snaps available and their RPC methods.\n */\n #getProtocolSnaps(scope: CaipChainId) {\n const allSnaps = this.#messenger.call('SnapController:getAll');\n const filteredSnaps = getRunnableSnaps(allSnaps);\n\n return filteredSnaps.reduce<ProtocolSnap[]>((accumulator, snap) => {\n const permissions = this.#messenger.call(\n 'PermissionController:getPermissions',\n snap.id,\n );\n\n if (permissions && hasProperty(permissions, SnapEndowments.Protocol)) {\n const permission = permissions[SnapEndowments.Protocol];\n const scopes = getProtocolCaveatScopes(permission);\n if (scopes && hasProperty(scopes, scope)) {\n accumulator.push({\n snapId: snap.id,\n methods: scopes[scope].methods,\n });\n }\n }\n\n return accumulator;\n }, []);\n }\n\n /**\n * Handle an incoming JSON-RPC request tied to a specific scope by routing\n * to either a protocol Snap or an account Snap.\n *\n * Note: Addresses are considered case sensitive by the MultichainRouter as\n * not all non-EVM chains are case insensitive.\n *\n * @param options - An options bag.\n * @param options.connectedAddresses - Addresses currently connected to the origin.\n * @param options.origin - The origin of the RPC request.\n * @param options.request - The JSON-RPC request.\n * @param options.scope - The CAIP-2 scope for the request.\n * @returns The response from the chosen Snap.\n * @throws If no handler was found.\n */\n async handleRequest({\n connectedAddresses,\n origin,\n scope,\n request: rawRequest,\n }: {\n connectedAddresses: CaipAccountId[];\n origin: string;\n scope: CaipChainId;\n request: JsonRpcRequest;\n }): Promise<Json> {\n // Explicitly block EVM scopes, just in case.\n assert(\n !scope.startsWith(KnownCaipNamespace.Eip155) &&\n !scope.startsWith('wallet:eip155'),\n );\n\n // Re-create the request to simplify and remove additional properties that may be present in MM middleware.\n const request = {\n jsonrpc: '2.0' as const,\n id: rawRequest.id ?? nanoid(),\n method: rawRequest.method,\n ...(rawRequest.params ? { params: rawRequest.params } : {}),\n };\n\n const { method, params } = request;\n\n // If the RPC request can be serviced by an account Snap, route it there.\n const accountId = await this.#getSnapAccountId(\n connectedAddresses,\n scope,\n request,\n );\n\n if (accountId) {\n return this.#withSnapKeyring(async ({ keyring }) =>\n keyring.submitRequest({\n origin,\n account: accountId,\n scope,\n method,\n params: params as JsonRpcParams,\n }),\n );\n }\n\n // If the RPC request cannot be serviced by an account Snap,\n // but has a protocol Snap available, route it there.\n const protocolSnaps = this.#getProtocolSnaps(scope);\n const protocolSnap = protocolSnaps.find((snap) =>\n snap.methods.includes(method),\n );\n\n if (protocolSnap) {\n return this.#messenger.call('SnapController:handleRequest', {\n snapId: protocolSnap.snapId,\n origin,\n request: {\n method: '',\n params: {\n request,\n scope,\n },\n },\n handler: HandlerType.OnProtocolRequest,\n }) as Promise<Json>;\n }\n\n // If no compatible account or protocol Snaps were found, throw.\n throw rpcErrors.methodNotFound();\n }\n\n /**\n * Get a list of metadata for supported accounts for a given scope from the client.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of metadata for the supported accounts.\n */\n #getSupportedAccountsMetadata(scope: CaipChainId): InternalAccount[] {\n return this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .filter((account: InternalAccount) => account.metadata.snap?.enabled);\n }\n\n /**\n * Get a list of supported methods for a given scope.\n * This combines both protocol and account Snaps supported methods.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of supported methods.\n */\n getSupportedMethods(scope: CaipChainId): string[] {\n const accountMethods = this.#getSupportedAccountsMetadata(scope).flatMap(\n (account) => account.methods,\n );\n\n const protocolMethods = this.#getProtocolSnaps(scope).flatMap(\n (snap) => snap.methods,\n );\n\n return Array.from(new Set([...accountMethods, ...protocolMethods]));\n }\n\n /**\n * Get a list of supported accounts for a given scope.\n *\n * @param scope - The CAIP-2 scope.\n * @returns A list of CAIP-10 addresses.\n */\n getSupportedAccounts(scope: CaipChainId): string[] {\n return this.#getSupportedAccountsMetadata(scope).map(\n (account) => `${scope}:${account.address}`,\n );\n }\n\n /**\n * Determine whether a given CAIP-2 scope is supported by the router.\n *\n * @param scope - The CAIP-2 scope.\n * @returns True if the router can service the scope, otherwise false.\n */\n isSupportedScope(scope: CaipChainId): boolean {\n const hasAccountSnap = this.#messenger\n .call('AccountsController:listMultichainAccounts', scope)\n .some((account: InternalAccount) => account.metadata.snap?.enabled);\n // We currently assume here that if one Snap exists that service the scope, we can service the scope generally.\n return hasAccountSnap || this.#getProtocolSnaps(scope).length > 0;\n }\n}\n"]}
|
|
@@ -55,7 +55,7 @@ export declare class MultichainRouter {
|
|
|
55
55
|
constructor({ messenger, withSnapKeyring }: MultichainRouterArgs);
|
|
56
56
|
/**
|
|
57
57
|
* Handle an incoming JSON-RPC request tied to a specific scope by routing
|
|
58
|
-
* to either a
|
|
58
|
+
* to either a protocol Snap or an account Snap.
|
|
59
59
|
*
|
|
60
60
|
* Note: Addresses are considered case sensitive by the MultichainRouter as
|
|
61
61
|
* not all non-EVM chains are case insensitive.
|
|
@@ -55,7 +55,7 @@ export declare class MultichainRouter {
|
|
|
55
55
|
constructor({ messenger, withSnapKeyring }: MultichainRouterArgs);
|
|
56
56
|
/**
|
|
57
57
|
* Handle an incoming JSON-RPC request tied to a specific scope by routing
|
|
58
|
-
* to either a
|
|
58
|
+
* to either a protocol Snap or an account Snap.
|
|
59
59
|
*
|
|
60
60
|
* Note: Addresses are considered case sensitive by the MultichainRouter as
|
|
61
61
|
* not all non-EVM chains are case insensitive.
|
|
@@ -107,7 +107,7 @@ export class MultichainRouter {
|
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
109
109
|
* Handle an incoming JSON-RPC request tied to a specific scope by routing
|
|
110
|
-
* to either a
|
|
110
|
+
* to either a protocol Snap or an account Snap.
|
|
111
111
|
*
|
|
112
112
|
* Note: Addresses are considered case sensitive by the MultichainRouter as
|
|
113
113
|
* not all non-EVM chains are case insensitive.
|