@metamask/snaps-controllers 20.0.6 → 21.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.
Files changed (30) hide show
  1. package/CHANGELOG.md +24 -1
  2. package/dist/snaps/SnapController.cjs +126 -19
  3. package/dist/snaps/SnapController.cjs.map +1 -1
  4. package/dist/snaps/SnapController.d.cts +24 -17
  5. package/dist/snaps/SnapController.d.cts.map +1 -1
  6. package/dist/snaps/SnapController.d.mts +24 -17
  7. package/dist/snaps/SnapController.d.mts.map +1 -1
  8. package/dist/snaps/SnapController.mjs +126 -19
  9. package/dist/snaps/SnapController.mjs.map +1 -1
  10. package/dist/snaps/registry/SnapRegistryController-method-action-types.cjs.map +1 -1
  11. package/dist/snaps/registry/SnapRegistryController-method-action-types.d.cts +12 -1
  12. package/dist/snaps/registry/SnapRegistryController-method-action-types.d.cts.map +1 -1
  13. package/dist/snaps/registry/SnapRegistryController-method-action-types.d.mts +12 -1
  14. package/dist/snaps/registry/SnapRegistryController-method-action-types.d.mts.map +1 -1
  15. package/dist/snaps/registry/SnapRegistryController-method-action-types.mjs.map +1 -1
  16. package/dist/snaps/registry/SnapRegistryController.cjs +28 -5
  17. package/dist/snaps/registry/SnapRegistryController.cjs.map +1 -1
  18. package/dist/snaps/registry/SnapRegistryController.d.cts +10 -1
  19. package/dist/snaps/registry/SnapRegistryController.d.cts.map +1 -1
  20. package/dist/snaps/registry/SnapRegistryController.d.mts +10 -1
  21. package/dist/snaps/registry/SnapRegistryController.d.mts.map +1 -1
  22. package/dist/snaps/registry/SnapRegistryController.mjs +28 -5
  23. package/dist/snaps/registry/SnapRegistryController.mjs.map +1 -1
  24. package/dist/snaps/registry/index.cjs.map +1 -1
  25. package/dist/snaps/registry/index.d.cts +1 -1
  26. package/dist/snaps/registry/index.d.cts.map +1 -1
  27. package/dist/snaps/registry/index.d.mts +1 -1
  28. package/dist/snaps/registry/index.d.mts.map +1 -1
  29. package/dist/snaps/registry/index.mjs.map +1 -1
  30. package/package.json +5 -4
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController-method-action-types.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SnapRegistryController } from './SnapRegistryController';\n\n/**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\nexport type SnapRegistryControllerRequestUpdateAction = {\n type: `SnapRegistryController:requestUpdate`;\n handler: SnapRegistryController['requestUpdate'];\n};\n\nexport type SnapRegistryControllerGetAction = {\n type: `SnapRegistryController:get`;\n handler: SnapRegistryController['get'];\n};\n\n/**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\nexport type SnapRegistryControllerResolveVersionAction = {\n type: `SnapRegistryController:resolveVersion`;\n handler: SnapRegistryController['resolveVersion'];\n};\n\n/**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\nexport type SnapRegistryControllerGetMetadataAction = {\n type: `SnapRegistryController:getMetadata`;\n handler: SnapRegistryController['getMetadata'];\n};\n\n/**\n * Union of all SnapRegistryController action types.\n */\nexport type SnapRegistryControllerMethodActions =\n | SnapRegistryControllerRequestUpdateAction\n | SnapRegistryControllerGetAction\n | SnapRegistryControllerResolveVersionAction\n | SnapRegistryControllerGetMetadataAction;\n"]}
1
+ {"version":3,"file":"SnapRegistryController-method-action-types.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SnapRegistryController } from './SnapRegistryController';\n\n/**\n * Request a periodic update of the registry database.\n *\n * This useful for updating the database with a longer interval than the\n * recent fetch threshold, which can help to reduce the number of fetches\n * while still keeping the database reasonably up to date.\n */\nexport type SnapRegistryControllerRequestPeriodicUpdateAction = {\n type: `SnapRegistryController:requestPeriodicUpdate`;\n handler: SnapRegistryController['requestPeriodicUpdate'];\n};\n\n/**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\nexport type SnapRegistryControllerRequestUpdateAction = {\n type: `SnapRegistryController:requestUpdate`;\n handler: SnapRegistryController['requestUpdate'];\n};\n\nexport type SnapRegistryControllerGetAction = {\n type: `SnapRegistryController:get`;\n handler: SnapRegistryController['get'];\n};\n\n/**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\nexport type SnapRegistryControllerResolveVersionAction = {\n type: `SnapRegistryController:resolveVersion`;\n handler: SnapRegistryController['resolveVersion'];\n};\n\n/**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\nexport type SnapRegistryControllerGetMetadataAction = {\n type: `SnapRegistryController:getMetadata`;\n handler: SnapRegistryController['getMetadata'];\n};\n\n/**\n * Union of all SnapRegistryController action types.\n */\nexport type SnapRegistryControllerMethodActions =\n | SnapRegistryControllerRequestPeriodicUpdateAction\n | SnapRegistryControllerRequestUpdateAction\n | SnapRegistryControllerGetAction\n | SnapRegistryControllerResolveVersionAction\n | SnapRegistryControllerGetMetadataAction;\n"]}
@@ -3,6 +3,17 @@
3
3
  * Do not edit manually.
4
4
  */
5
5
  import type { SnapRegistryController } from "./SnapRegistryController.cjs";
6
+ /**
7
+ * Request a periodic update of the registry database.
8
+ *
9
+ * This useful for updating the database with a longer interval than the
10
+ * recent fetch threshold, which can help to reduce the number of fetches
11
+ * while still keeping the database reasonably up to date.
12
+ */
13
+ export type SnapRegistryControllerRequestPeriodicUpdateAction = {
14
+ type: `SnapRegistryController:requestPeriodicUpdate`;
15
+ handler: SnapRegistryController['requestPeriodicUpdate'];
16
+ };
6
17
  /**
7
18
  * Triggers an update of the registry database.
8
19
  *
@@ -42,5 +53,5 @@ export type SnapRegistryControllerGetMetadataAction = {
42
53
  /**
43
54
  * Union of all SnapRegistryController action types.
44
55
  */
45
- export type SnapRegistryControllerMethodActions = SnapRegistryControllerRequestUpdateAction | SnapRegistryControllerGetAction | SnapRegistryControllerResolveVersionAction | SnapRegistryControllerGetMetadataAction;
56
+ export type SnapRegistryControllerMethodActions = SnapRegistryControllerRequestPeriodicUpdateAction | SnapRegistryControllerRequestUpdateAction | SnapRegistryControllerGetAction | SnapRegistryControllerResolveVersionAction | SnapRegistryControllerGetMetadataAction;
46
57
  //# sourceMappingURL=SnapRegistryController-method-action-types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController-method-action-types.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,qCAAiC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,yCAAyC,GAAG;IACtD,IAAI,EAAE,sCAAsC,CAAC;IAC7C,OAAO,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,uCAAuC,CAAC;IAC9C,OAAO,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,yCAAyC,GACzC,+BAA+B,GAC/B,0CAA0C,GAC1C,uCAAuC,CAAC"}
1
+ {"version":3,"file":"SnapRegistryController-method-action-types.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,qCAAiC;AAEvE;;;;;;GAMG;AACH,MAAM,MAAM,iDAAiD,GAAG;IAC9D,IAAI,EAAE,8CAA8C,CAAC;IACrD,OAAO,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;CAC1D,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yCAAyC,GAAG;IACtD,IAAI,EAAE,sCAAsC,CAAC;IAC7C,OAAO,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,uCAAuC,CAAC;IAC9C,OAAO,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,iDAAiD,GACjD,yCAAyC,GACzC,+BAA+B,GAC/B,0CAA0C,GAC1C,uCAAuC,CAAC"}
@@ -3,6 +3,17 @@
3
3
  * Do not edit manually.
4
4
  */
5
5
  import type { SnapRegistryController } from "./SnapRegistryController.mjs";
6
+ /**
7
+ * Request a periodic update of the registry database.
8
+ *
9
+ * This useful for updating the database with a longer interval than the
10
+ * recent fetch threshold, which can help to reduce the number of fetches
11
+ * while still keeping the database reasonably up to date.
12
+ */
13
+ export type SnapRegistryControllerRequestPeriodicUpdateAction = {
14
+ type: `SnapRegistryController:requestPeriodicUpdate`;
15
+ handler: SnapRegistryController['requestPeriodicUpdate'];
16
+ };
6
17
  /**
7
18
  * Triggers an update of the registry database.
8
19
  *
@@ -42,5 +53,5 @@ export type SnapRegistryControllerGetMetadataAction = {
42
53
  /**
43
54
  * Union of all SnapRegistryController action types.
44
55
  */
45
- export type SnapRegistryControllerMethodActions = SnapRegistryControllerRequestUpdateAction | SnapRegistryControllerGetAction | SnapRegistryControllerResolveVersionAction | SnapRegistryControllerGetMetadataAction;
56
+ export type SnapRegistryControllerMethodActions = SnapRegistryControllerRequestPeriodicUpdateAction | SnapRegistryControllerRequestUpdateAction | SnapRegistryControllerGetAction | SnapRegistryControllerResolveVersionAction | SnapRegistryControllerGetMetadataAction;
46
57
  //# sourceMappingURL=SnapRegistryController-method-action-types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController-method-action-types.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,qCAAiC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,yCAAyC,GAAG;IACtD,IAAI,EAAE,sCAAsC,CAAC;IAC7C,OAAO,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,uCAAuC,CAAC;IAC9C,OAAO,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,yCAAyC,GACzC,+BAA+B,GAC/B,0CAA0C,GAC1C,uCAAuC,CAAC"}
1
+ {"version":3,"file":"SnapRegistryController-method-action-types.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,qCAAiC;AAEvE;;;;;;GAMG;AACH,MAAM,MAAM,iDAAiD,GAAG;IAC9D,IAAI,EAAE,8CAA8C,CAAC;IACrD,OAAO,EAAE,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;CAC1D,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yCAAyC,GAAG;IACtD,IAAI,EAAE,sCAAsC,CAAC;IAC7C,OAAO,EAAE,sBAAsB,CAAC,eAAe,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,uCAAuC,CAAC;IAC9C,OAAO,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAC3C,iDAAiD,GACjD,yCAAyC,GACzC,+BAA+B,GAC/B,0CAA0C,GAC1C,uCAAuC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController-method-action-types.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SnapRegistryController } from './SnapRegistryController';\n\n/**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\nexport type SnapRegistryControllerRequestUpdateAction = {\n type: `SnapRegistryController:requestUpdate`;\n handler: SnapRegistryController['requestUpdate'];\n};\n\nexport type SnapRegistryControllerGetAction = {\n type: `SnapRegistryController:get`;\n handler: SnapRegistryController['get'];\n};\n\n/**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\nexport type SnapRegistryControllerResolveVersionAction = {\n type: `SnapRegistryController:resolveVersion`;\n handler: SnapRegistryController['resolveVersion'];\n};\n\n/**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\nexport type SnapRegistryControllerGetMetadataAction = {\n type: `SnapRegistryController:getMetadata`;\n handler: SnapRegistryController['getMetadata'];\n};\n\n/**\n * Union of all SnapRegistryController action types.\n */\nexport type SnapRegistryControllerMethodActions =\n | SnapRegistryControllerRequestUpdateAction\n | SnapRegistryControllerGetAction\n | SnapRegistryControllerResolveVersionAction\n | SnapRegistryControllerGetMetadataAction;\n"]}
1
+ {"version":3,"file":"SnapRegistryController-method-action-types.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SnapRegistryController } from './SnapRegistryController';\n\n/**\n * Request a periodic update of the registry database.\n *\n * This useful for updating the database with a longer interval than the\n * recent fetch threshold, which can help to reduce the number of fetches\n * while still keeping the database reasonably up to date.\n */\nexport type SnapRegistryControllerRequestPeriodicUpdateAction = {\n type: `SnapRegistryController:requestPeriodicUpdate`;\n handler: SnapRegistryController['requestPeriodicUpdate'];\n};\n\n/**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\nexport type SnapRegistryControllerRequestUpdateAction = {\n type: `SnapRegistryController:requestUpdate`;\n handler: SnapRegistryController['requestUpdate'];\n};\n\nexport type SnapRegistryControllerGetAction = {\n type: `SnapRegistryController:get`;\n handler: SnapRegistryController['get'];\n};\n\n/**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\nexport type SnapRegistryControllerResolveVersionAction = {\n type: `SnapRegistryController:resolveVersion`;\n handler: SnapRegistryController['resolveVersion'];\n};\n\n/**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\nexport type SnapRegistryControllerGetMetadataAction = {\n type: `SnapRegistryController:getMetadata`;\n handler: SnapRegistryController['getMetadata'];\n};\n\n/**\n * Union of all SnapRegistryController action types.\n */\nexport type SnapRegistryControllerMethodActions =\n | SnapRegistryControllerRequestPeriodicUpdateAction\n | SnapRegistryControllerRequestUpdateAction\n | SnapRegistryControllerGetAction\n | SnapRegistryControllerResolveVersionAction\n | SnapRegistryControllerGetMetadataAction;\n"]}
@@ -15,6 +15,7 @@ const MESSENGER_EXPOSED_METHODS = [
15
15
  'getMetadata',
16
16
  'resolveVersion',
17
17
  'requestUpdate',
18
+ 'requestPeriodicUpdate',
18
19
  ];
19
20
  const defaultState = {
20
21
  database: null,
@@ -29,11 +30,12 @@ class SnapRegistryController extends base_controller_1.BaseController {
29
30
  #fetchFunction;
30
31
  #recentFetchThreshold;
31
32
  #refetchOnAllowlistMiss;
33
+ #periodicFetchThreshold;
32
34
  #currentUpdate;
33
35
  constructor({ messenger, state, url = {
34
36
  registry: SNAP_REGISTRY_URL,
35
37
  signature: SNAP_REGISTRY_SIGNATURE_URL,
36
- }, publicKey = DEFAULT_PUBLIC_KEY, clientConfig, fetchFunction = globalThis.fetch.bind(undefined), recentFetchThreshold = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Minute), refetchOnAllowlistMiss = true, }) {
38
+ }, publicKey = DEFAULT_PUBLIC_KEY, clientConfig, fetchFunction = globalThis.fetch.bind(undefined), recentFetchThreshold = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Minute), periodicFetchThreshold = (0, utils_1.inMilliseconds)(4, utils_1.Duration.Hour), refetchOnAllowlistMiss = true, }) {
37
39
  super({
38
40
  messenger,
39
41
  metadata: {
@@ -73,13 +75,34 @@ class SnapRegistryController extends base_controller_1.BaseController {
73
75
  this.#clientConfig = clientConfig;
74
76
  this.#fetchFunction = fetchFunction;
75
77
  this.#recentFetchThreshold = recentFetchThreshold;
78
+ this.#periodicFetchThreshold = periodicFetchThreshold;
76
79
  this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;
77
80
  this.#currentUpdate = null;
78
81
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
79
82
  }
80
- #wasRecentlyFetched() {
81
- return (this.state.lastUpdated &&
82
- Date.now() - this.state.lastUpdated < this.#recentFetchThreshold);
83
+ /**
84
+ * Get whether the registry was recently fetched.
85
+ *
86
+ * @param threshold - The threshold in milliseconds to consider the registry
87
+ * as recently fetched.
88
+ * @returns Whether the registry was recently fetched.
89
+ */
90
+ #wasRecentlyFetched(threshold = this.#recentFetchThreshold) {
91
+ return (this.state.lastUpdated && Date.now() - this.state.lastUpdated < threshold);
92
+ }
93
+ /**
94
+ * Request a periodic update of the registry database.
95
+ *
96
+ * This useful for updating the database with a longer interval than the
97
+ * recent fetch threshold, which can help to reduce the number of fetches
98
+ * while still keeping the database reasonably up to date.
99
+ */
100
+ async requestPeriodicUpdate() {
101
+ if (this.#wasRecentlyFetched(this.#periodicFetchThreshold)) {
102
+ this.messenger.publish('SnapRegistryController:registryUpdated', false);
103
+ return;
104
+ }
105
+ await this.requestUpdate();
83
106
  }
84
107
  /**
85
108
  * Triggers an update of the registry database.
@@ -102,7 +125,7 @@ class SnapRegistryController extends base_controller_1.BaseController {
102
125
  /**
103
126
  * Updates the registry database if the registry hasn't been updated recently.
104
127
  *
105
- * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.
128
+ * NOTE: SHOULD NOT be called directly, instead `requestUpdate` should be used.
106
129
  */
107
130
  async #update() {
108
131
  // No-op if we recently fetched the registry.
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapsRegistryDatabase,\n SignatureStruct,\n} from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Infer } from '@metamask/superstruct';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type { SnapRegistryControllerMethodActions } from './SnapRegistryController-method-action-types';\nimport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nimport { SnapRegistryStatus } from './types';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type ClientConfig = {\n type: 'extension' | 'mobile';\n version: SemVerVersion;\n};\n\nexport type SnapRegistryControllerArgs = {\n messenger: SnapRegistryControllerMessenger;\n state?: SnapRegistryControllerState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n clientConfig: ClientConfig;\n};\n\nexport type SnapRegistryControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerActions =\n | SnapRegistryControllerGetStateAction\n | SnapRegistryControllerMethodActions;\n\nexport type SnapRegistryControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerRegistryUpdatedEvent = {\n type: `${typeof controllerName}:registryUpdated`;\n payload: [databaseUpdated: boolean];\n};\n\nexport type SnapRegistryControllerEvents =\n | SnapRegistryControllerStateChangeEvent\n | SnapRegistryControllerRegistryUpdatedEvent;\n\nexport type SnapRegistryControllerMessenger = Messenger<\n typeof controllerName,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents\n>;\n\nexport type SnapRegistryControllerState = {\n database: SnapsRegistryDatabase | null;\n signature: string | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapRegistryController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'get',\n 'getMetadata',\n 'resolveVersion',\n 'requestUpdate',\n] as const;\n\nconst defaultState = {\n database: null,\n signature: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class SnapRegistryController extends BaseController<\n typeof controllerName,\n SnapRegistryControllerState,\n SnapRegistryControllerMessenger\n> {\n readonly #url: JsonSnapsRegistryUrl;\n\n readonly #publicKey: Hex;\n\n readonly #clientConfig: ClientConfig;\n\n readonly #fetchFunction: typeof fetch;\n\n readonly #recentFetchThreshold: number;\n\n readonly #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n clientConfig,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: SnapRegistryControllerArgs) {\n super({\n messenger,\n metadata: {\n database: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n signature: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n lastUpdated: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n databaseUnavailable: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#clientConfig = clientConfig;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async requestUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n try {\n const [database, signature] = await Promise.all([\n this.#safeFetch(this.#url.registry),\n this.#safeFetch(this.#url.signature),\n ]);\n\n const signatureJson = JSON.parse(signature);\n\n // If the signature matches the existing state, we can skip verification and don't need to update the database.\n if (signatureJson.signature === this.state.signature) {\n this.update((state) => {\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.#verifySignature(database, signatureJson);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n state.signature = signatureJson.signature;\n });\n\n this.messenger.publish('SnapRegistryController:registryUpdated', true);\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.requestUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapRegistryInfo,\n refetch = false,\n ): Promise<SnapRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n const clientRange = version?.clientVersions?.[this.#clientConfig.type];\n const isCompatible =\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange);\n if (version && version.checksum === snapInfo.checksum && isCompatible) {\n return { status: SnapRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapRegistryStatus.Unavailable\n : SnapRegistryStatus.Unverified,\n };\n }\n\n async get(\n snaps: SnapRegistryRequest,\n skipRefetch = false,\n ): Promise<Record<string, SnapRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo, skipRefetch);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const compatibleVersions = Object.entries(versions).reduce<SemVerVersion[]>(\n (accumulator, [version, metadata]) => {\n const clientRange = metadata.clientVersions?.[this.#clientConfig.type];\n if (\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange)\n ) {\n accumulator.push(version as SemVerVersion);\n }\n\n return accumulator;\n },\n [],\n );\n\n const targetVersion = getTargetVersion(compatibleVersions, versionRange);\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n getMetadata(snapId: string): SnapRegistryMetadata | null {\n return this.state?.database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n */\n async #verifySignature(\n database: string,\n signature: Infer<typeof SignatureStruct>,\n ) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await verify({\n registry: database,\n signature,\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url, { cache: 'no-cache' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
1
+ {"version":3,"file":"SnapRegistryController.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapsRegistryDatabase,\n SignatureStruct,\n} from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Infer } from '@metamask/superstruct';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type { SnapRegistryControllerMethodActions } from './SnapRegistryController-method-action-types';\nimport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nimport { SnapRegistryStatus } from './types';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type ClientConfig = {\n type: 'extension' | 'mobile';\n version: SemVerVersion;\n};\n\nexport type SnapRegistryControllerArgs = {\n messenger: SnapRegistryControllerMessenger;\n state?: SnapRegistryControllerState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n periodicFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n clientConfig: ClientConfig;\n};\n\nexport type SnapRegistryControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerActions =\n | SnapRegistryControllerGetStateAction\n | SnapRegistryControllerMethodActions;\n\nexport type SnapRegistryControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerRegistryUpdatedEvent = {\n type: `${typeof controllerName}:registryUpdated`;\n payload: [databaseUpdated: boolean];\n};\n\nexport type SnapRegistryControllerEvents =\n | SnapRegistryControllerStateChangeEvent\n | SnapRegistryControllerRegistryUpdatedEvent;\n\nexport type SnapRegistryControllerMessenger = Messenger<\n typeof controllerName,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents\n>;\n\nexport type SnapRegistryControllerState = {\n database: SnapsRegistryDatabase | null;\n signature: string | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapRegistryController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'get',\n 'getMetadata',\n 'resolveVersion',\n 'requestUpdate',\n 'requestPeriodicUpdate',\n] as const;\n\nconst defaultState = {\n database: null,\n signature: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class SnapRegistryController extends BaseController<\n typeof controllerName,\n SnapRegistryControllerState,\n SnapRegistryControllerMessenger\n> {\n readonly #url: JsonSnapsRegistryUrl;\n\n readonly #publicKey: Hex;\n\n readonly #clientConfig: ClientConfig;\n\n readonly #fetchFunction: typeof fetch;\n\n readonly #recentFetchThreshold: number;\n\n readonly #refetchOnAllowlistMiss: boolean;\n\n readonly #periodicFetchThreshold: number;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n clientConfig,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n periodicFetchThreshold = inMilliseconds(4, Duration.Hour),\n refetchOnAllowlistMiss = true,\n }: SnapRegistryControllerArgs) {\n super({\n messenger,\n metadata: {\n database: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n signature: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n lastUpdated: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n databaseUnavailable: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#clientConfig = clientConfig;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#periodicFetchThreshold = periodicFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Get whether the registry was recently fetched.\n *\n * @param threshold - The threshold in milliseconds to consider the registry\n * as recently fetched.\n * @returns Whether the registry was recently fetched.\n */\n #wasRecentlyFetched(threshold = this.#recentFetchThreshold) {\n return (\n this.state.lastUpdated && Date.now() - this.state.lastUpdated < threshold\n );\n }\n\n /**\n * Request a periodic update of the registry database.\n *\n * This useful for updating the database with a longer interval than the\n * recent fetch threshold, which can help to reduce the number of fetches\n * while still keeping the database reasonably up to date.\n */\n async requestPeriodicUpdate() {\n if (this.#wasRecentlyFetched(this.#periodicFetchThreshold)) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.requestUpdate();\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async requestUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `requestUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n try {\n const [database, signature] = await Promise.all([\n this.#safeFetch(this.#url.registry),\n this.#safeFetch(this.#url.signature),\n ]);\n\n const signatureJson = JSON.parse(signature);\n\n // If the signature matches the existing state, we can skip verification and don't need to update the database.\n if (signatureJson.signature === this.state.signature) {\n this.update((state) => {\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.#verifySignature(database, signatureJson);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n state.signature = signatureJson.signature;\n });\n\n this.messenger.publish('SnapRegistryController:registryUpdated', true);\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.requestUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapRegistryInfo,\n refetch = false,\n ): Promise<SnapRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n const clientRange = version?.clientVersions?.[this.#clientConfig.type];\n const isCompatible =\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange);\n if (version && version.checksum === snapInfo.checksum && isCompatible) {\n return { status: SnapRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapRegistryStatus.Unavailable\n : SnapRegistryStatus.Unverified,\n };\n }\n\n async get(\n snaps: SnapRegistryRequest,\n skipRefetch = false,\n ): Promise<Record<string, SnapRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo, skipRefetch);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const compatibleVersions = Object.entries(versions).reduce<SemVerVersion[]>(\n (accumulator, [version, metadata]) => {\n const clientRange = metadata.clientVersions?.[this.#clientConfig.type];\n if (\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange)\n ) {\n accumulator.push(version as SemVerVersion);\n }\n\n return accumulator;\n },\n [],\n );\n\n const targetVersion = getTargetVersion(compatibleVersions, versionRange);\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n getMetadata(snapId: string): SnapRegistryMetadata | null {\n return this.state?.database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n */\n async #verifySignature(\n database: string,\n signature: Infer<typeof SignatureStruct>,\n ) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await verify({\n registry: database,\n signature,\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url, { cache: 'no-cache' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
@@ -19,6 +19,7 @@ export type SnapRegistryControllerArgs = {
19
19
  fetchFunction?: typeof fetch;
20
20
  url?: JsonSnapsRegistryUrl;
21
21
  recentFetchThreshold?: number;
22
+ periodicFetchThreshold?: number;
22
23
  refetchOnAllowlistMiss?: boolean;
23
24
  publicKey?: Hex;
24
25
  clientConfig: ClientConfig;
@@ -41,7 +42,15 @@ export type SnapRegistryControllerState = {
41
42
  declare const controllerName = "SnapRegistryController";
42
43
  export declare class SnapRegistryController extends BaseController<typeof controllerName, SnapRegistryControllerState, SnapRegistryControllerMessenger> {
43
44
  #private;
44
- constructor({ messenger, state, url, publicKey, clientConfig, fetchFunction, recentFetchThreshold, refetchOnAllowlistMiss, }: SnapRegistryControllerArgs);
45
+ constructor({ messenger, state, url, publicKey, clientConfig, fetchFunction, recentFetchThreshold, periodicFetchThreshold, refetchOnAllowlistMiss, }: SnapRegistryControllerArgs);
46
+ /**
47
+ * Request a periodic update of the registry database.
48
+ *
49
+ * This useful for updating the database with a longer interval than the
50
+ * recent fetch threshold, which can help to reduce the number of fetches
51
+ * while still keeping the database reasonably up to date.
52
+ */
53
+ requestPeriodicUpdate(): Promise<void>;
45
54
  /**
46
55
  * Triggers an update of the registry database.
47
56
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,qBAAqB,EAEtB,iCAAiC;AAIlC,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,wBAAwB;AASvE,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EACnB,oBAAgB;AAYjB,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC7B,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,KAAK,CAAC;IAC7B,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,MAAM,MAAM,sCAAsC,GAAG,0BAA0B,CAC7E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,GAAG,OAAO,cAAc,kBAAkB,CAAC;IACjD,OAAO,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,4BAA4B,GACpC,sCAAsC,GACtC,0CAA0C,CAAC;AAE/C,MAAM,MAAM,+BAA+B,GAAG,SAAS,CACrD,OAAO,cAAc,EACrB,6BAA6B,EAC7B,4BAA4B,CAC7B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAgBhD,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAea,EACV,SAAS,EACT,KAAK,EACL,GAGC,EACD,SAA8B,EAC9B,YAAY,EACZ,aAAgD,EAChD,oBAAyD,EACzD,sBAA6B,GAC9B,EAAE,0BAA0B;IAwD7B;;;;OAIG;IACG,aAAa;IAoHb,GAAG,CACP,KAAK,EAAE,mBAAmB,EAC1B,WAAW,UAAQ,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAW9C;;;;;;;OAOG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,WAAW,EACzB,OAAO,UAAQ,GACd,OAAO,CAAC,WAAW,CAAC;IA8CvB;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;CAyCzD"}
1
+ {"version":3,"file":"SnapRegistryController.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ export type SnapRegistryControllerArgs = {
19
19
  fetchFunction?: typeof fetch;
20
20
  url?: JsonSnapsRegistryUrl;
21
21
  recentFetchThreshold?: number;
22
+ periodicFetchThreshold?: number;
22
23
  refetchOnAllowlistMiss?: boolean;
23
24
  publicKey?: Hex;
24
25
  clientConfig: ClientConfig;
@@ -41,7 +42,15 @@ export type SnapRegistryControllerState = {
41
42
  declare const controllerName = "SnapRegistryController";
42
43
  export declare class SnapRegistryController extends BaseController<typeof controllerName, SnapRegistryControllerState, SnapRegistryControllerMessenger> {
43
44
  #private;
44
- constructor({ messenger, state, url, publicKey, clientConfig, fetchFunction, recentFetchThreshold, refetchOnAllowlistMiss, }: SnapRegistryControllerArgs);
45
+ constructor({ messenger, state, url, publicKey, clientConfig, fetchFunction, recentFetchThreshold, periodicFetchThreshold, refetchOnAllowlistMiss, }: SnapRegistryControllerArgs);
46
+ /**
47
+ * Request a periodic update of the registry database.
48
+ *
49
+ * This useful for updating the database with a longer interval than the
50
+ * recent fetch threshold, which can help to reduce the number of fetches
51
+ * while still keeping the database reasonably up to date.
52
+ */
53
+ requestPeriodicUpdate(): Promise<void>;
45
54
  /**
46
55
  * Triggers an update of the registry database.
47
56
  *
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EACV,qBAAqB,EAEtB,iCAAiC;AAIlC,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,wBAAwB;AASvE,OAAO,KAAK,EAAE,mCAAmC,EAAE,yDAAqD;AACxG,OAAO,KAAK,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EACnB,oBAAgB;AAYjB,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC7B,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,+BAA+B,CAAC;IAC3C,KAAK,CAAC,EAAE,2BAA2B,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,KAAK,CAAC;IAC7B,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG,wBAAwB,CACzE,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GACrC,oCAAoC,GACpC,mCAAmC,CAAC;AAExC,MAAM,MAAM,sCAAsC,GAAG,0BAA0B,CAC7E,OAAO,cAAc,EACrB,2BAA2B,CAC5B,CAAC;AAEF,MAAM,MAAM,0CAA0C,GAAG;IACvD,IAAI,EAAE,GAAG,OAAO,cAAc,kBAAkB,CAAC;IACjD,OAAO,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,4BAA4B,GACpC,sCAAsC,GACtC,0CAA0C,CAAC;AAE/C,MAAM,MAAM,+BAA+B,GAAG,SAAS,CACrD,OAAO,cAAc,EACrB,6BAA6B,EAC7B,4BAA4B,CAC7B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,QAAA,MAAM,cAAc,2BAA2B,CAAC;AAgBhD,qBAAa,sBAAuB,SAAQ,cAAc,CACxD,OAAO,cAAc,EACrB,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAea,EACV,SAAS,EACT,KAAK,EACL,GAGC,EACD,SAA8B,EAC9B,YAAY,EACZ,aAAgD,EAChD,oBAAyD,EACzD,sBAA6B,GAC9B,EAAE,0BAA0B;IAwD7B;;;;OAIG;IACG,aAAa;IAoHb,GAAG,CACP,KAAK,EAAE,mBAAmB,EAC1B,WAAW,UAAQ,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAW9C;;;;;;;OAOG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,WAAW,EACzB,OAAO,UAAQ,GACd,OAAO,CAAC,WAAW,CAAC;IA8CvB;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;CAyCzD"}
1
+ {"version":3,"file":"SnapRegistryController.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ const MESSENGER_EXPOSED_METHODS = [
12
12
  'getMetadata',
13
13
  'resolveVersion',
14
14
  'requestUpdate',
15
+ 'requestPeriodicUpdate',
15
16
  ];
16
17
  const defaultState = {
17
18
  database: null,
@@ -26,11 +27,12 @@ export class SnapRegistryController extends BaseController {
26
27
  #fetchFunction;
27
28
  #recentFetchThreshold;
28
29
  #refetchOnAllowlistMiss;
30
+ #periodicFetchThreshold;
29
31
  #currentUpdate;
30
32
  constructor({ messenger, state, url = {
31
33
  registry: SNAP_REGISTRY_URL,
32
34
  signature: SNAP_REGISTRY_SIGNATURE_URL,
33
- }, publicKey = DEFAULT_PUBLIC_KEY, clientConfig, fetchFunction = globalThis.fetch.bind(undefined), recentFetchThreshold = inMilliseconds(5, Duration.Minute), refetchOnAllowlistMiss = true, }) {
35
+ }, publicKey = DEFAULT_PUBLIC_KEY, clientConfig, fetchFunction = globalThis.fetch.bind(undefined), recentFetchThreshold = inMilliseconds(5, Duration.Minute), periodicFetchThreshold = inMilliseconds(4, Duration.Hour), refetchOnAllowlistMiss = true, }) {
34
36
  super({
35
37
  messenger,
36
38
  metadata: {
@@ -70,13 +72,34 @@ export class SnapRegistryController extends BaseController {
70
72
  this.#clientConfig = clientConfig;
71
73
  this.#fetchFunction = fetchFunction;
72
74
  this.#recentFetchThreshold = recentFetchThreshold;
75
+ this.#periodicFetchThreshold = periodicFetchThreshold;
73
76
  this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;
74
77
  this.#currentUpdate = null;
75
78
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
76
79
  }
77
- #wasRecentlyFetched() {
78
- return (this.state.lastUpdated &&
79
- Date.now() - this.state.lastUpdated < this.#recentFetchThreshold);
80
+ /**
81
+ * Get whether the registry was recently fetched.
82
+ *
83
+ * @param threshold - The threshold in milliseconds to consider the registry
84
+ * as recently fetched.
85
+ * @returns Whether the registry was recently fetched.
86
+ */
87
+ #wasRecentlyFetched(threshold = this.#recentFetchThreshold) {
88
+ return (this.state.lastUpdated && Date.now() - this.state.lastUpdated < threshold);
89
+ }
90
+ /**
91
+ * Request a periodic update of the registry database.
92
+ *
93
+ * This useful for updating the database with a longer interval than the
94
+ * recent fetch threshold, which can help to reduce the number of fetches
95
+ * while still keeping the database reasonably up to date.
96
+ */
97
+ async requestPeriodicUpdate() {
98
+ if (this.#wasRecentlyFetched(this.#periodicFetchThreshold)) {
99
+ this.messenger.publish('SnapRegistryController:registryUpdated', false);
100
+ return;
101
+ }
102
+ await this.requestUpdate();
80
103
  }
81
104
  /**
82
105
  * Triggers an update of the registry database.
@@ -99,7 +122,7 @@ export class SnapRegistryController extends BaseController {
99
122
  /**
100
123
  * Updates the registry database if the registry hasn't been updated recently.
101
124
  *
102
- * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.
125
+ * NOTE: SHOULD NOT be called directly, instead `requestUpdate` should be used.
103
126
  */
104
127
  async #update() {
105
128
  // No-op if we recently fetched the registry.
@@ -1 +1 @@
1
- {"version":3,"file":"SnapRegistryController.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapsRegistryDatabase,\n SignatureStruct,\n} from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Infer } from '@metamask/superstruct';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type { SnapRegistryControllerMethodActions } from './SnapRegistryController-method-action-types';\nimport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nimport { SnapRegistryStatus } from './types';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type ClientConfig = {\n type: 'extension' | 'mobile';\n version: SemVerVersion;\n};\n\nexport type SnapRegistryControllerArgs = {\n messenger: SnapRegistryControllerMessenger;\n state?: SnapRegistryControllerState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n clientConfig: ClientConfig;\n};\n\nexport type SnapRegistryControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerActions =\n | SnapRegistryControllerGetStateAction\n | SnapRegistryControllerMethodActions;\n\nexport type SnapRegistryControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerRegistryUpdatedEvent = {\n type: `${typeof controllerName}:registryUpdated`;\n payload: [databaseUpdated: boolean];\n};\n\nexport type SnapRegistryControllerEvents =\n | SnapRegistryControllerStateChangeEvent\n | SnapRegistryControllerRegistryUpdatedEvent;\n\nexport type SnapRegistryControllerMessenger = Messenger<\n typeof controllerName,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents\n>;\n\nexport type SnapRegistryControllerState = {\n database: SnapsRegistryDatabase | null;\n signature: string | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapRegistryController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'get',\n 'getMetadata',\n 'resolveVersion',\n 'requestUpdate',\n] as const;\n\nconst defaultState = {\n database: null,\n signature: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class SnapRegistryController extends BaseController<\n typeof controllerName,\n SnapRegistryControllerState,\n SnapRegistryControllerMessenger\n> {\n readonly #url: JsonSnapsRegistryUrl;\n\n readonly #publicKey: Hex;\n\n readonly #clientConfig: ClientConfig;\n\n readonly #fetchFunction: typeof fetch;\n\n readonly #recentFetchThreshold: number;\n\n readonly #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n clientConfig,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: SnapRegistryControllerArgs) {\n super({\n messenger,\n metadata: {\n database: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n signature: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n lastUpdated: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n databaseUnavailable: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#clientConfig = clientConfig;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async requestUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n try {\n const [database, signature] = await Promise.all([\n this.#safeFetch(this.#url.registry),\n this.#safeFetch(this.#url.signature),\n ]);\n\n const signatureJson = JSON.parse(signature);\n\n // If the signature matches the existing state, we can skip verification and don't need to update the database.\n if (signatureJson.signature === this.state.signature) {\n this.update((state) => {\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.#verifySignature(database, signatureJson);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n state.signature = signatureJson.signature;\n });\n\n this.messenger.publish('SnapRegistryController:registryUpdated', true);\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.requestUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapRegistryInfo,\n refetch = false,\n ): Promise<SnapRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n const clientRange = version?.clientVersions?.[this.#clientConfig.type];\n const isCompatible =\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange);\n if (version && version.checksum === snapInfo.checksum && isCompatible) {\n return { status: SnapRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapRegistryStatus.Unavailable\n : SnapRegistryStatus.Unverified,\n };\n }\n\n async get(\n snaps: SnapRegistryRequest,\n skipRefetch = false,\n ): Promise<Record<string, SnapRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo, skipRefetch);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const compatibleVersions = Object.entries(versions).reduce<SemVerVersion[]>(\n (accumulator, [version, metadata]) => {\n const clientRange = metadata.clientVersions?.[this.#clientConfig.type];\n if (\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange)\n ) {\n accumulator.push(version as SemVerVersion);\n }\n\n return accumulator;\n },\n [],\n );\n\n const targetVersion = getTargetVersion(compatibleVersions, versionRange);\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n getMetadata(snapId: string): SnapRegistryMetadata | null {\n return this.state?.database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n */\n async #verifySignature(\n database: string,\n signature: Infer<typeof SignatureStruct>,\n ) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await verify({\n registry: database,\n signature,\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url, { cache: 'no-cache' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
1
+ {"version":3,"file":"SnapRegistryController.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/SnapRegistryController.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAM3D,OAAO,EAAE,MAAM,EAAE,iCAAiC;AAClD,OAAO,EAAE,gBAAgB,EAAE,8BAA8B;AAGzD,OAAO,EACL,MAAM,EACN,mBAAmB,EACnB,QAAQ,EACR,cAAc,EACd,qBAAqB,EACtB,wBAAwB;AASzB,OAAO,EAAE,kBAAkB,EAAE,oBAAgB;AAE7C,MAAM,iBAAiB,GACrB,wDAAwD,CAAC;AAE3D,MAAM,2BAA2B,GAC/B,yDAAyD,CAAC;AAE5D,MAAM,kBAAkB,GACtB,sEAAsE,CAAC;AA4DzE,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEhD,MAAM,yBAAyB,GAAG;IAChC,KAAK;IACL,aAAa;IACb,gBAAgB;IAChB,eAAe;IACf,uBAAuB;CACf,CAAC;AAEX,MAAM,YAAY,GAAG;IACnB,QAAQ,EAAE,IAAI;IACd,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,IAAI;IACjB,mBAAmB,EAAE,KAAK;CAC3B,CAAC;AAEF,MAAM,OAAO,sBAAuB,SAAQ,cAI3C;IACU,IAAI,CAAuB;IAE3B,UAAU,CAAM;IAEhB,aAAa,CAAe;IAE5B,cAAc,CAAe;IAE7B,qBAAqB,CAAS;IAE9B,uBAAuB,CAAU;IAEjC,uBAAuB,CAAS;IAEzC,cAAc,CAAuB;IAErC,YAAY,EACV,SAAS,EACT,KAAK,EACL,GAAG,GAAG;QACJ,QAAQ,EAAE,iBAAiB;QAC3B,SAAS,EAAE,2BAA2B;KACvC,EACD,SAAS,GAAG,kBAAkB,EAC9B,YAAY,EACZ,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAChD,oBAAoB,GAAG,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,EACzD,sBAAsB,GAAG,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,EACzD,sBAAsB,GAAG,IAAI,GACF;QAC3B,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ,EAAE;gBACR,QAAQ,EAAE;oBACR,kBAAkB,EAAE,IAAI;oBACxB,OAAO,EAAE,IAAI;oBACb,sBAAsB,EAAE,KAAK;oBAC7B,QAAQ,EAAE,IAAI;iBACf;gBACD,SAAS,EAAE;oBACT,kBAAkB,EAAE,IAAI;oBACxB,OAAO,EAAE,IAAI;oBACb,sBAAsB,EAAE,IAAI;oBAC5B,QAAQ,EAAE,KAAK;iBAChB;gBACD,WAAW,EAAE;oBACX,kBAAkB,EAAE,IAAI;oBACxB,OAAO,EAAE,IAAI;oBACb,sBAAsB,EAAE,IAAI;oBAC5B,QAAQ,EAAE,KAAK;iBAChB;gBACD,mBAAmB,EAAE;oBACnB,kBAAkB,EAAE,IAAI;oBACxB,OAAO,EAAE,IAAI;oBACb,sBAAsB,EAAE,IAAI;oBAC5B,QAAQ,EAAE,KAAK;iBAChB;aACF;YACD,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE;gBACL,GAAG,YAAY;gBACf,GAAG,KAAK;aACT;SACF,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;QAClD,IAAI,CAAC,uBAAuB,GAAG,sBAAsB,CAAC;QACtD,IAAI,CAAC,uBAAuB,GAAG,sBAAsB,CAAC;QACtD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAE3B,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,SAAS,GAAG,IAAI,CAAC,qBAAqB;QACxD,OAAO,CACL,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS,CAC1E,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,qBAAqB;QACzB,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,uBAAuB,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,aAAa;QACjB,0CAA0C;QAC1C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,cAAc,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,0DAA0D;QAC1D,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QACvC,CAAC;QACD,MAAM,IAAI,CAAC,cAAc,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACX,6CAA6C;QAC7C,IAAI,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAC/B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC9C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;gBACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;aACrC,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAE5C,+GAA+G;YAC/G,IAAI,aAAa,CAAC,SAAS,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;gBACrD,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;oBACpB,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAC/B,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC;gBACpC,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;gBACxE,OAAO;YACT,CAAC;YAED,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YAErD,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACtC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC/B,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC;gBAClC,KAAK,CAAC,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;YAC5C,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,wCAAwC,EAAE,IAAI,CAAC,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;YACT,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,KAAK,CAAC,mBAAmB,GAAG,IAAI,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACjC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7B,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU,CACd,MAAc,EACd,QAA0B,EAC1B,OAAO,GAAG,KAAK;QAEf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAE3C,MAAM,YAAY,GAAG,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3D,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;gBACpB,OAAO,CACL,OAAO,CAAC,EAAE,KAAK,MAAM;oBACrB,qBAAqB,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAC9D,CAAC;YACJ,CAAC;YAED,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO;gBACL,MAAM,EAAE,kBAAkB,CAAC,OAAO;gBAClC,MAAM,EAAE,YAAY,CAAC,MAAM;aAC5B,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,OAAO,EAAE,cAAc,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACvE,MAAM,YAAY,GAChB,CAAC,WAAW;YACZ,qBAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACjE,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC;YACtE,OAAO,EAAE,MAAM,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC;QACjD,CAAC;QACD,4EAA4E;QAC5E,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7C,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACjD,CAAC;QACD,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB;gBACpC,CAAC,CAAC,kBAAkB,CAAC,WAAW;gBAChC,CAAC,CAAC,kBAAkB,CAAC,UAAU;SAClC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CACP,KAA0B,EAC1B,WAAW,GAAG,KAAK;QAEnB,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAEjC,KAAK,EAAE,eAAe,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE;YAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YACpE,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC;YAClC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;YACrB,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,cAAc,CAClB,MAAc,EACd,YAAyB,EACzB,OAAO,GAAG,KAAK;QAEf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;QAEnE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1D,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;QACzD,CAAC;QAED,oFAAoF;QACpF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CACxD,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE;YACnC,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACvE,IACE,CAAC,WAAW;gBACZ,qBAAqB,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,EAC9D,CAAC;gBACD,WAAW,CAAC,IAAI,CAAC,OAAwB,CAAC,CAAC;YAC7C,CAAC;YAED,OAAO,WAAW,CAAC;QACrB,CAAC,EACD,EAAE,CACH,CAAC;QAEF,MAAM,aAAa,GAAG,gBAAgB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAEzE,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/D,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;QACzD,CAAC;QAED,oFAAoF;QACpF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,6DAA6D;QAC7D,mBAAmB,CAAC,aAAa,CAAC,CAAC;QACnC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,MAAc;QACxB,OAAO,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACvE,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,SAAwC;QAExC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;QAEnD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;YACzB,QAAQ,EAAE,QAAQ;YAClB,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,GAAG,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;CACF","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n SnapsRegistryDatabase,\n SignatureStruct,\n} from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Infer } from '@metamask/superstruct';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type { SnapRegistryControllerMethodActions } from './SnapRegistryController-method-action-types';\nimport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nimport { SnapRegistryStatus } from './types';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type ClientConfig = {\n type: 'extension' | 'mobile';\n version: SemVerVersion;\n};\n\nexport type SnapRegistryControllerArgs = {\n messenger: SnapRegistryControllerMessenger;\n state?: SnapRegistryControllerState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n periodicFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n clientConfig: ClientConfig;\n};\n\nexport type SnapRegistryControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerActions =\n | SnapRegistryControllerGetStateAction\n | SnapRegistryControllerMethodActions;\n\nexport type SnapRegistryControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapRegistryControllerState\n>;\n\nexport type SnapRegistryControllerRegistryUpdatedEvent = {\n type: `${typeof controllerName}:registryUpdated`;\n payload: [databaseUpdated: boolean];\n};\n\nexport type SnapRegistryControllerEvents =\n | SnapRegistryControllerStateChangeEvent\n | SnapRegistryControllerRegistryUpdatedEvent;\n\nexport type SnapRegistryControllerMessenger = Messenger<\n typeof controllerName,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents\n>;\n\nexport type SnapRegistryControllerState = {\n database: SnapsRegistryDatabase | null;\n signature: string | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapRegistryController';\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'get',\n 'getMetadata',\n 'resolveVersion',\n 'requestUpdate',\n 'requestPeriodicUpdate',\n] as const;\n\nconst defaultState = {\n database: null,\n signature: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class SnapRegistryController extends BaseController<\n typeof controllerName,\n SnapRegistryControllerState,\n SnapRegistryControllerMessenger\n> {\n readonly #url: JsonSnapsRegistryUrl;\n\n readonly #publicKey: Hex;\n\n readonly #clientConfig: ClientConfig;\n\n readonly #fetchFunction: typeof fetch;\n\n readonly #recentFetchThreshold: number;\n\n readonly #refetchOnAllowlistMiss: boolean;\n\n readonly #periodicFetchThreshold: number;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n clientConfig,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n periodicFetchThreshold = inMilliseconds(4, Duration.Hour),\n refetchOnAllowlistMiss = true,\n }: SnapRegistryControllerArgs) {\n super({\n messenger,\n metadata: {\n database: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n signature: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n lastUpdated: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n databaseUnavailable: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#clientConfig = clientConfig;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#periodicFetchThreshold = periodicFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Get whether the registry was recently fetched.\n *\n * @param threshold - The threshold in milliseconds to consider the registry\n * as recently fetched.\n * @returns Whether the registry was recently fetched.\n */\n #wasRecentlyFetched(threshold = this.#recentFetchThreshold) {\n return (\n this.state.lastUpdated && Date.now() - this.state.lastUpdated < threshold\n );\n }\n\n /**\n * Request a periodic update of the registry database.\n *\n * This useful for updating the database with a longer interval than the\n * recent fetch threshold, which can help to reduce the number of fetches\n * while still keeping the database reasonably up to date.\n */\n async requestPeriodicUpdate() {\n if (this.#wasRecentlyFetched(this.#periodicFetchThreshold)) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.requestUpdate();\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async requestUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `requestUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n try {\n const [database, signature] = await Promise.all([\n this.#safeFetch(this.#url.registry),\n this.#safeFetch(this.#url.signature),\n ]);\n\n const signatureJson = JSON.parse(signature);\n\n // If the signature matches the existing state, we can skip verification and don't need to update the database.\n if (signatureJson.signature === this.state.signature) {\n this.update((state) => {\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n this.messenger.publish('SnapRegistryController:registryUpdated', false);\n return;\n }\n\n await this.#verifySignature(database, signatureJson);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n state.signature = signatureJson.signature;\n });\n\n this.messenger.publish('SnapRegistryController:registryUpdated', true);\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.requestUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapRegistryInfo,\n refetch = false,\n ): Promise<SnapRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n const clientRange = version?.clientVersions?.[this.#clientConfig.type];\n const isCompatible =\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange);\n if (version && version.checksum === snapInfo.checksum && isCompatible) {\n return { status: SnapRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapRegistryStatus.Unavailable\n : SnapRegistryStatus.Unverified,\n };\n }\n\n async get(\n snaps: SnapRegistryRequest,\n skipRefetch = false,\n ): Promise<Record<string, SnapRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo, skipRefetch);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const compatibleVersions = Object.entries(versions).reduce<SemVerVersion[]>(\n (accumulator, [version, metadata]) => {\n const clientRange = metadata.clientVersions?.[this.#clientConfig.type];\n if (\n !clientRange ||\n satisfiesVersionRange(this.#clientConfig.version, clientRange)\n ) {\n accumulator.push(version as SemVerVersion);\n }\n\n return accumulator;\n },\n [],\n );\n\n const targetVersion = getTargetVersion(compatibleVersions, versionRange);\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.requestUpdate();\n return this.resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID, if available, without updating registry.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n getMetadata(snapId: string): SnapRegistryMetadata | null {\n return this.state?.database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n */\n async #verifySignature(\n database: string,\n signature: Infer<typeof SignatureStruct>,\n ) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await verify({\n registry: database,\n signature,\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url, { cache: 'no-cache' });\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":";;;AAUA,uEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAa/B,qCAA6C;AAApC,2GAAA,kBAAkB,OAAA","sourcesContent":["export type {\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents,\n SnapRegistryControllerArgs,\n SnapRegistryControllerGetStateAction,\n SnapRegistryControllerMessenger,\n SnapRegistryControllerState,\n SnapRegistryControllerStateChangeEvent,\n SnapRegistryControllerRegistryUpdatedEvent,\n} from './SnapRegistryController';\nexport { SnapRegistryController } from './SnapRegistryController';\nexport type {\n SnapRegistryControllerGetAction,\n SnapRegistryControllerGetMetadataAction,\n SnapRegistryControllerRequestUpdateAction,\n SnapRegistryControllerResolveVersionAction,\n} from './SnapRegistryController-method-action-types';\nexport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nexport { SnapRegistryStatus } from './types';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":";;;AAWA,uEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAa/B,qCAA6C;AAApC,2GAAA,kBAAkB,OAAA","sourcesContent":["export type {\n ClientConfig,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents,\n SnapRegistryControllerArgs,\n SnapRegistryControllerGetStateAction,\n SnapRegistryControllerMessenger,\n SnapRegistryControllerState,\n SnapRegistryControllerStateChangeEvent,\n SnapRegistryControllerRegistryUpdatedEvent,\n} from './SnapRegistryController';\nexport { SnapRegistryController } from './SnapRegistryController';\nexport type {\n SnapRegistryControllerGetAction,\n SnapRegistryControllerGetMetadataAction,\n SnapRegistryControllerRequestUpdateAction,\n SnapRegistryControllerResolveVersionAction,\n} from './SnapRegistryController-method-action-types';\nexport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nexport { SnapRegistryStatus } from './types';\n"]}
@@ -1,4 +1,4 @@
1
- export type { SnapRegistryControllerActions, SnapRegistryControllerEvents, SnapRegistryControllerArgs, SnapRegistryControllerGetStateAction, SnapRegistryControllerMessenger, SnapRegistryControllerState, SnapRegistryControllerStateChangeEvent, SnapRegistryControllerRegistryUpdatedEvent, } from "./SnapRegistryController.cjs";
1
+ export type { ClientConfig, SnapRegistryControllerActions, SnapRegistryControllerEvents, SnapRegistryControllerArgs, SnapRegistryControllerGetStateAction, SnapRegistryControllerMessenger, SnapRegistryControllerState, SnapRegistryControllerStateChangeEvent, SnapRegistryControllerRegistryUpdatedEvent, } from "./SnapRegistryController.cjs";
2
2
  export { SnapRegistryController } from "./SnapRegistryController.cjs";
3
3
  export type { SnapRegistryControllerGetAction, SnapRegistryControllerGetMetadataAction, SnapRegistryControllerRequestUpdateAction, SnapRegistryControllerResolveVersionAction, } from "./SnapRegistryController-method-action-types.cjs";
4
4
  export type { SnapRegistryInfo, SnapRegistryMetadata, SnapRegistryRequest, SnapRegistryResult, } from "./types.cjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,6BAA6B,EAC7B,4BAA4B,EAC5B,0BAA0B,EAC1B,oCAAoC,EACpC,+BAA+B,EAC/B,2BAA2B,EAC3B,sCAAsC,EACtC,0CAA0C,GAC3C,qCAAiC;AAClC,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,YAAY,EACV,+BAA+B,EAC/B,uCAAuC,EACvC,yCAAyC,EACzC,0CAA0C,GAC3C,yDAAqD;AACtD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,oBAAgB;AACjB,OAAO,EAAE,kBAAkB,EAAE,oBAAgB"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,6BAA6B,EAC7B,4BAA4B,EAC5B,0BAA0B,EAC1B,oCAAoC,EACpC,+BAA+B,EAC/B,2BAA2B,EAC3B,sCAAsC,EACtC,0CAA0C,GAC3C,qCAAiC;AAClC,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,YAAY,EACV,+BAA+B,EAC/B,uCAAuC,EACvC,yCAAyC,EACzC,0CAA0C,GAC3C,yDAAqD;AACtD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,oBAAgB;AACjB,OAAO,EAAE,kBAAkB,EAAE,oBAAgB"}
@@ -1,4 +1,4 @@
1
- export type { SnapRegistryControllerActions, SnapRegistryControllerEvents, SnapRegistryControllerArgs, SnapRegistryControllerGetStateAction, SnapRegistryControllerMessenger, SnapRegistryControllerState, SnapRegistryControllerStateChangeEvent, SnapRegistryControllerRegistryUpdatedEvent, } from "./SnapRegistryController.mjs";
1
+ export type { ClientConfig, SnapRegistryControllerActions, SnapRegistryControllerEvents, SnapRegistryControllerArgs, SnapRegistryControllerGetStateAction, SnapRegistryControllerMessenger, SnapRegistryControllerState, SnapRegistryControllerStateChangeEvent, SnapRegistryControllerRegistryUpdatedEvent, } from "./SnapRegistryController.mjs";
2
2
  export { SnapRegistryController } from "./SnapRegistryController.mjs";
3
3
  export type { SnapRegistryControllerGetAction, SnapRegistryControllerGetMetadataAction, SnapRegistryControllerRequestUpdateAction, SnapRegistryControllerResolveVersionAction, } from "./SnapRegistryController-method-action-types.mjs";
4
4
  export type { SnapRegistryInfo, SnapRegistryMetadata, SnapRegistryRequest, SnapRegistryResult, } from "./types.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,6BAA6B,EAC7B,4BAA4B,EAC5B,0BAA0B,EAC1B,oCAAoC,EACpC,+BAA+B,EAC/B,2BAA2B,EAC3B,sCAAsC,EACtC,0CAA0C,GAC3C,qCAAiC;AAClC,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,YAAY,EACV,+BAA+B,EAC/B,uCAAuC,EACvC,yCAAyC,EACzC,0CAA0C,GAC3C,yDAAqD;AACtD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,oBAAgB;AACjB,OAAO,EAAE,kBAAkB,EAAE,oBAAgB"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,6BAA6B,EAC7B,4BAA4B,EAC5B,0BAA0B,EAC1B,oCAAoC,EACpC,+BAA+B,EAC/B,2BAA2B,EAC3B,sCAAsC,EACtC,0CAA0C,GAC3C,qCAAiC;AAClC,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAClE,YAAY,EACV,+BAA+B,EAC/B,uCAAuC,EACvC,yCAAyC,EACzC,0CAA0C,GAC3C,yDAAqD;AACtD,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,oBAAgB;AACjB,OAAO,EAAE,kBAAkB,EAAE,oBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAalE,OAAO,EAAE,kBAAkB,EAAE,oBAAgB","sourcesContent":["export type {\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents,\n SnapRegistryControllerArgs,\n SnapRegistryControllerGetStateAction,\n SnapRegistryControllerMessenger,\n SnapRegistryControllerState,\n SnapRegistryControllerStateChangeEvent,\n SnapRegistryControllerRegistryUpdatedEvent,\n} from './SnapRegistryController';\nexport { SnapRegistryController } from './SnapRegistryController';\nexport type {\n SnapRegistryControllerGetAction,\n SnapRegistryControllerGetMetadataAction,\n SnapRegistryControllerRequestUpdateAction,\n SnapRegistryControllerResolveVersionAction,\n} from './SnapRegistryController-method-action-types';\nexport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nexport { SnapRegistryStatus } from './types';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAalE,OAAO,EAAE,kBAAkB,EAAE,oBAAgB","sourcesContent":["export type {\n ClientConfig,\n SnapRegistryControllerActions,\n SnapRegistryControllerEvents,\n SnapRegistryControllerArgs,\n SnapRegistryControllerGetStateAction,\n SnapRegistryControllerMessenger,\n SnapRegistryControllerState,\n SnapRegistryControllerStateChangeEvent,\n SnapRegistryControllerRegistryUpdatedEvent,\n} from './SnapRegistryController';\nexport { SnapRegistryController } from './SnapRegistryController';\nexport type {\n SnapRegistryControllerGetAction,\n SnapRegistryControllerGetMetadataAction,\n SnapRegistryControllerRequestUpdateAction,\n SnapRegistryControllerResolveVersionAction,\n} from './SnapRegistryController-method-action-types';\nexport type {\n SnapRegistryInfo,\n SnapRegistryMetadata,\n SnapRegistryRequest,\n SnapRegistryResult,\n} from './types';\nexport { SnapRegistryStatus } from './types';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/snaps-controllers",
3
- "version": "20.0.6",
3
+ "version": "21.0.0",
4
4
  "description": "Controllers for MetaMask Snaps",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -81,7 +81,8 @@
81
81
  "test:watch": "jest --watch"
82
82
  },
83
83
  "dependencies": {
84
- "@metamask/approval-controller": "^9.0.1",
84
+ "@metamask/analytics-controller": "^1.1.1",
85
+ "@metamask/approval-controller": "^9.0.2",
85
86
  "@metamask/base-controller": "^9.1.0",
86
87
  "@metamask/json-rpc-engine": "^10.5.0",
87
88
  "@metamask/json-rpc-middleware-stream": "^8.0.8",
@@ -95,7 +96,7 @@
95
96
  "@metamask/snaps-rpc-methods": "^17.0.0",
96
97
  "@metamask/snaps-sdk": "^11.1.1",
97
98
  "@metamask/snaps-utils": "^12.2.1",
98
- "@metamask/storage-service": "^1.0.1",
99
+ "@metamask/storage-service": "^1.0.2",
99
100
  "@metamask/superstruct": "^3.2.1",
100
101
  "@metamask/utils": "^11.11.0",
101
102
  "@xstate/fsm": "^2.0.0",
@@ -145,7 +146,7 @@
145
146
  "ts-node": "^10.9.1",
146
147
  "tsx": "^4.20.3",
147
148
  "typescript": "~5.3.3",
148
- "vite": "^6.4.1",
149
+ "vite": "^6.4.3",
149
150
  "vite-plugin-node-polyfills": "^0.23.0",
150
151
  "vite-tsconfig-paths": "^4.0.5",
151
152
  "vitest": "^3.1.1"