@metamask/snaps-controllers 0.29.0 → 0.31.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 (46) hide show
  1. package/dist/cronjob/CronjobController.js +11 -8
  2. package/dist/cronjob/CronjobController.js.map +1 -1
  3. package/dist/fsm.js +5 -5
  4. package/dist/fsm.js.map +1 -1
  5. package/dist/multichain/MultiChainController.js +12 -20
  6. package/dist/multichain/MultiChainController.js.map +1 -1
  7. package/dist/multichain/matching.js +3 -4
  8. package/dist/multichain/matching.js.map +1 -1
  9. package/dist/services/iframe/IframeExecutionService.js +1 -2
  10. package/dist/services/iframe/IframeExecutionService.js.map +1 -1
  11. package/dist/snaps/RequestQueue.js +3 -6
  12. package/dist/snaps/RequestQueue.js.map +1 -1
  13. package/dist/snaps/SnapController.d.ts +7 -5
  14. package/dist/snaps/SnapController.js +253 -171
  15. package/dist/snaps/SnapController.js.map +1 -1
  16. package/dist/snaps/endowments/cronjob.js +2 -3
  17. package/dist/snaps/endowments/cronjob.js.map +1 -1
  18. package/dist/snaps/endowments/enum.d.ts +2 -1
  19. package/dist/snaps/endowments/enum.js +1 -0
  20. package/dist/snaps/endowments/enum.js.map +1 -1
  21. package/dist/snaps/endowments/index.d.ts +9 -0
  22. package/dist/snaps/endowments/index.js +8 -1
  23. package/dist/snaps/endowments/index.js.map +1 -1
  24. package/dist/snaps/endowments/keyring.js +3 -4
  25. package/dist/snaps/endowments/keyring.js.map +1 -1
  26. package/dist/snaps/endowments/rpc.js +2 -2
  27. package/dist/snaps/endowments/rpc.js.map +1 -1
  28. package/dist/snaps/endowments/transaction-insight.js +4 -5
  29. package/dist/snaps/endowments/transaction-insight.js.map +1 -1
  30. package/dist/snaps/endowments/web-assembly.d.ts +13 -0
  31. package/dist/snaps/endowments/web-assembly.js +30 -0
  32. package/dist/snaps/endowments/web-assembly.js.map +1 -0
  33. package/dist/snaps/location/http.js +9 -3
  34. package/dist/snaps/location/http.js.map +1 -1
  35. package/dist/snaps/location/local.js +1 -1
  36. package/dist/snaps/location/local.js.map +1 -1
  37. package/dist/snaps/location/location.js +2 -3
  38. package/dist/snaps/location/location.js.map +1 -1
  39. package/dist/snaps/location/npm.js +11 -8
  40. package/dist/snaps/location/npm.js.map +1 -1
  41. package/dist/snaps/registry/json.js +5 -7
  42. package/dist/snaps/registry/json.js.map +1 -1
  43. package/package.json +35 -15
  44. package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.d.ts +0 -3
  45. package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js +0 -34
  46. package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js.map +0 -1
@@ -10,20 +10,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
12
  };
13
- var __rest = (this && this.__rest) || function (s, e) {
14
- var t = {};
15
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
- t[p] = s[p];
17
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
- t[p[i]] = s[p[i]];
21
- }
22
- return t;
23
- };
24
- var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_registry, _SnapController_maxIdleTime, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_removeSnapFromSubjects, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchSnap, _SnapController_processSnapPermissions, _SnapController_getRpcRequestHandler, _SnapController_executeWithTimeout, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isValidUpdate;
13
+ var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_registry, _SnapController_maxIdleTime, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_removeSnapFromSubjects, _SnapController_createApproval, _SnapController_updateApproval, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchSnap, _SnapController_processSnapPermissions, _SnapController_validateSnapPermissions, _SnapController_getRpcRequestHandler, _SnapController_executeWithTimeout, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isValidUpdate;
25
14
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.SnapController = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
15
+ exports.SnapController = exports.SNAP_APPROVAL_RESULT = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
27
16
  const base_controller_1 = require("@metamask/base-controller");
28
17
  const rpc_methods_1 = require("@metamask/rpc-methods");
29
18
  const snaps_utils_1 = require("@metamask/snaps-utils");
@@ -45,6 +34,7 @@ exports.controllerName = 'SnapController';
45
34
  // TODO: Figure out how to name these
46
35
  exports.SNAP_APPROVAL_INSTALL = 'wallet_installSnap';
47
36
  exports.SNAP_APPROVAL_UPDATE = 'wallet_updateSnap';
37
+ exports.SNAP_APPROVAL_RESULT = 'wallet_installSnapResult';
48
38
  const TRUNCATED_SNAP_PROPERTIES = new Set([
49
39
  'initialPermissions',
50
40
  'id',
@@ -82,7 +72,6 @@ const name = 'SnapController';
82
72
  */
83
73
  class SnapController extends base_controller_1.BaseControllerV2 {
84
74
  constructor({ closeAllConnections, messenger, state, environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), registry = new registry_1.JsonSnapsRegistry(), maxIdleTime = (0, utils_1.inMilliseconds)(30, utils_1.Duration.Second), maxRequestTime = (0, utils_1.inMilliseconds)(60, utils_1.Duration.Second), fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, detectSnapLocation: detectSnapLocationFunction = location_1.detectSnapLocation, }) {
85
- var _a, _b;
86
75
  super({
87
76
  messenger,
88
77
  metadata: {
@@ -103,9 +92,12 @@ class SnapController extends base_controller_1.BaseControllerV2 {
103
92
  persist: (snaps) => {
104
93
  return Object.values(snaps)
105
94
  .map((snap) => {
106
- return Object.assign(Object.assign({}, snap), { sourceCode: __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snap.id).sourceCode,
95
+ return {
96
+ ...snap,
97
+ sourceCode: __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snap.id).sourceCode,
107
98
  // At the time state is rehydrated, no snap will be running.
108
- status: snaps_utils_1.SnapStatus.Stopped });
99
+ status: snaps_utils_1.SnapStatus.Stopped,
100
+ };
109
101
  })
110
102
  .reduce((memo, snap) => {
111
103
  memo[snap.id] = snap;
@@ -116,12 +108,18 @@ class SnapController extends base_controller_1.BaseControllerV2 {
116
108
  },
117
109
  },
118
110
  name,
119
- state: Object.assign(Object.assign({}, defaultState), Object.assign(Object.assign({}, state), { snaps: Object.values((_a = state === null || state === void 0 ? void 0 : state.snaps) !== null && _a !== void 0 ? _a : {}).reduce((memo, snap) => {
120
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
121
- const { sourceCode } = snap, rest = __rest(snap, ["sourceCode"]);
122
- memo[snap.id] = rest;
123
- return memo;
124
- }, {}) })),
111
+ state: {
112
+ ...defaultState,
113
+ ...{
114
+ ...state,
115
+ snaps: Object.values(state?.snaps ?? {}).reduce((memo, snap) => {
116
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
117
+ const { sourceCode, ...rest } = snap;
118
+ memo[snap.id] = rest;
119
+ return memo;
120
+ }, {}),
121
+ },
122
+ },
125
123
  });
126
124
  _SnapController_instances.add(this);
127
125
  _SnapController_closeAllConnections.set(this, void 0);
@@ -159,13 +157,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
159
157
  /* eslint-enable @typescript-eslint/unbound-method */
160
158
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_initializeStateMachine).call(this);
161
159
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_registerMessageHandlers).call(this);
162
- Object.values((_b = state === null || state === void 0 ? void 0 : state.snaps) !== null && _b !== void 0 ? _b : {}).forEach((snap) => {
163
- var _a, _b;
164
- return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snap.id, {
165
- sourceCode: snap.sourceCode,
166
- state: (_b = (_a = state === null || state === void 0 ? void 0 : state.snapStates) === null || _a === void 0 ? void 0 : _a[snap.id]) !== null && _b !== void 0 ? _b : null,
167
- });
168
- });
160
+ Object.values(state?.snaps ?? {}).forEach((snap) => __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snap.id, {
161
+ sourceCode: snap.sourceCode,
162
+ state: state?.snapStates?.[snap.id] ?? null,
163
+ }));
169
164
  }
170
165
  /**
171
166
  * Checks all installed snaps against the block list and
@@ -388,7 +383,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
388
383
  addSnapError(snapError) {
389
384
  this.update((state) => {
390
385
  const id = (0, nanoid_1.nanoid)();
391
- state.snapErrors[id] = Object.assign(Object.assign({}, snapError), { internalID: id });
386
+ state.snapErrors[id] = {
387
+ ...snapError,
388
+ internalID: id,
389
+ };
392
390
  });
393
391
  }
394
392
  /**
@@ -419,7 +417,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
419
417
  */
420
418
  async getSnapState(snapId) {
421
419
  const { state } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
422
- return state !== null && state !== void 0 ? state : null;
420
+ return state ?? null;
423
421
  }
424
422
  /**
425
423
  * Completely clear the controller's state: delete all associated data,
@@ -517,13 +515,12 @@ class SnapController extends base_controller_1.BaseControllerV2 {
517
515
  * @returns The serialized permitted snaps for the origin.
518
516
  */
519
517
  getPermittedSnaps(origin) {
520
- var _a, _b, _c, _d, _e;
521
- const permissions = (_a = this.messagingSystem.call('PermissionController:getPermissions', origin)) !== null && _a !== void 0 ? _a : {};
522
- const snaps = (_e = (_d = (_c = (_b = permissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]) === null || _b === void 0 ? void 0 : _b.caveats) === null || _c === void 0 ? void 0 : _c.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : {};
518
+ const permissions = this.messagingSystem.call('PermissionController:getPermissions', origin) ?? {};
519
+ const snaps = permissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)?.value ?? {};
523
520
  return Object.keys(snaps).reduce((permittedSnaps, snapId) => {
524
521
  const snap = this.get(snapId);
525
522
  const truncatedSnap = this.getTruncated(snapId);
526
- if (truncatedSnap && (snap === null || snap === void 0 ? void 0 : snap.status) !== snaps_utils_1.SnapStatus.Installing) {
523
+ if (truncatedSnap && snap?.status !== snaps_utils_1.SnapStatus.Installing) {
527
524
  permittedSnaps[snapId] = truncatedSnap;
528
525
  }
529
526
  return permittedSnaps;
@@ -542,12 +539,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
542
539
  async installSnaps(origin, requestedSnaps) {
543
540
  const result = {};
544
541
  const snapIds = Object.keys(requestedSnaps);
545
- // Existing snaps may need to be updated
546
- const pendingUpdates = snapIds.filter((snapId) => this.has(snapId));
547
- // Non-existing snaps will need to be installed
548
- const pendingInstalls = snapIds.filter((snapId) => !pendingUpdates.includes(snapId));
542
+ const pendingUpdates = [];
543
+ const pendingInstalls = [];
549
544
  try {
550
545
  for (const [snapId, { version: rawVersion }] of Object.entries(requestedSnaps)) {
546
+ (0, snaps_utils_1.assertIsValidSnapId)(snapId);
551
547
  const [error, version] = (0, snaps_utils_1.resolveVersionRange)(rawVersion);
552
548
  if (error) {
553
549
  throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
@@ -556,8 +552,16 @@ class SnapController extends base_controller_1.BaseControllerV2 {
556
552
  if (!(0, snaps_utils_1.isSnapPermitted)(permissions, snapId)) {
557
553
  throw eth_rpc_errors_1.ethErrors.provider.unauthorized(`Not authorized to install snap "${snapId}". Request the permission for the snap before attempting to install it.`);
558
554
  }
559
- const isUpdate = pendingUpdates.includes(snapId);
555
+ const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, {
556
+ versionRange: version,
557
+ fetch: __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"),
558
+ allowLocal: __classPrivateFieldGet(this, _SnapController_featureFlags, "f").allowLocalSnaps,
559
+ });
560
+ // Existing snaps may need to be updated, unless they should be re-installed (e.g. local snaps)
561
+ // Everything else is treated as an install
562
+ const isUpdate = this.has(snapId) && !location.shouldAlwaysReload;
560
563
  if (isUpdate && __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_isValidUpdate).call(this, snapId, version)) {
564
+ pendingUpdates.push(snapId);
561
565
  let rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
562
566
  if (rollbackSnapshot === undefined) {
563
567
  const prevSourceCode = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId).sourceCode;
@@ -569,7 +573,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
569
573
  throw new Error('This snap is already being updated.');
570
574
  }
571
575
  }
572
- result[snapId] = await this.processRequestedSnap(origin, snapId, version);
576
+ else if (!isUpdate) {
577
+ pendingInstalls.push(snapId);
578
+ }
579
+ result[snapId] = await this.processRequestedSnap(origin, snapId, location, version);
573
580
  }
574
581
  snapIds.forEach((snapId) => __classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").delete(snapId));
575
582
  }
@@ -589,16 +596,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
589
596
  *
590
597
  * @param origin - The origin requesting the snap.
591
598
  * @param snapId - The id of the snap.
599
+ * @param location - The location implementation of the snap.
592
600
  * @param versionRange - The semver range of the snap to install.
593
601
  * @returns The resulting snap object, or an error if something went wrong.
594
602
  */
595
- async processRequestedSnap(origin, snapId, versionRange) {
596
- (0, snaps_utils_1.validateSnapId)(snapId);
597
- const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, {
598
- versionRange,
599
- fetch: __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"),
600
- allowLocal: __classPrivateFieldGet(this, _SnapController_featureFlags, "f").allowLocalSnaps,
601
- });
603
+ async processRequestedSnap(origin, snapId, location, versionRange) {
602
604
  const existingSnap = this.getTruncated(snapId);
603
605
  // For devX we always re-install local snaps.
604
606
  if (existingSnap && !location.shouldAlwaysReload) {
@@ -606,35 +608,50 @@ class SnapController extends base_controller_1.BaseControllerV2 {
606
608
  return existingSnap;
607
609
  }
608
610
  if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").dappsCanUpdateSnaps === true) {
609
- const updateResult = await this.updateSnap(origin, snapId, location, versionRange);
610
- if (updateResult === null) {
611
- throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Snap "${snapId}@${existingSnap.version}" is already installed. Couldn't update to a version inside requested "${versionRange}" range.`);
612
- }
613
- return updateResult;
611
+ return await this.updateSnap(origin, snapId, location, versionRange);
614
612
  }
615
613
  throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Version mismatch with already installed snap. ${snapId}@${existingSnap.version} doesn't satisfy requested version ${versionRange}.`);
616
614
  }
615
+ let pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
616
+ origin,
617
+ snapId,
618
+ type: exports.SNAP_APPROVAL_INSTALL,
619
+ });
617
620
  // Existing snaps must be stopped before overwriting
618
621
  if (existingSnap && this.isRunning(snapId)) {
619
622
  await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
620
623
  }
624
+ // Existing snaps that should be re-installed should not maintain their existing permissions
625
+ if (existingSnap && location.shouldAlwaysReload) {
626
+ this.revokeAllSnapPermissions(snapId);
627
+ }
621
628
  try {
622
629
  const { sourceCode } = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_add).call(this, {
623
630
  origin,
624
631
  id: snapId,
625
632
  location,
626
633
  });
627
- await this.authorize(origin, snapId);
634
+ await this.authorize(snapId, pendingApproval);
635
+ pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
636
+ origin,
637
+ snapId,
638
+ type: exports.SNAP_APPROVAL_RESULT,
639
+ });
628
640
  await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, {
629
641
  snapId,
630
642
  sourceCode,
631
643
  });
632
644
  const truncated = this.getTruncatedExpect(snapId);
645
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, { loading: false });
633
646
  this.messagingSystem.publish(`SnapController:snapInstalled`, truncated);
634
647
  return truncated;
635
648
  }
636
649
  catch (error) {
637
650
  (0, snaps_utils_1.logError)(`Error when adding snap.`, error);
651
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
652
+ loading: false,
653
+ error: error instanceof Error ? error.message : error.toString(),
654
+ });
638
655
  throw error;
639
656
  }
640
657
  }
@@ -652,88 +669,102 @@ class SnapController extends base_controller_1.BaseControllerV2 {
652
669
  *
653
670
  * @param origin - The origin requesting the snap update.
654
671
  * @param snapId - The id of the Snap to be updated.
655
- * @param location - Optional location that was already used during installation flow.
672
+ * @param location - The location implementation of the snap.
656
673
  * @param newVersionRange - A semver version range in which the maximum version will be chosen.
657
674
  * @returns The snap metadata if updated, `null` otherwise.
658
675
  */
659
676
  async updateSnap(origin, snapId, location, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
660
- var _a;
661
- const snap = this.getExpect(snapId);
662
677
  if (!(0, utils_1.isValidSemVerRange)(newVersionRange)) {
663
678
  throw new Error(`Received invalid snap version range: "${newVersionRange}".`);
664
679
  }
665
- const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
666
- const newVersion = newSnap.manifest.result.version;
667
- if (!(0, utils_1.gtVersion)(newVersion, snap.version)) {
668
- (0, snaps_utils_1.logWarning)(`Tried updating snap "${snapId}" within "${newVersionRange}" version range, but newer version "${snap.version}" is already installed`);
669
- return null;
670
- }
671
- await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
672
- version: newVersion,
673
- checksum: newSnap.manifest.result.source.shasum,
674
- });
675
- const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
676
- const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
677
- const id = (0, nanoid_1.nanoid)();
678
- const _b = (await this.messagingSystem.call('ApprovalController:addRequest', {
680
+ let pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
679
681
  origin,
680
- id,
682
+ snapId,
681
683
  type: exports.SNAP_APPROVAL_UPDATE,
682
- requestData: {
683
- // First two keys mirror installation params
684
- metadata: { id, origin: snapId, dappOrigin: origin },
684
+ });
685
+ try {
686
+ const snap = this.getExpect(snapId);
687
+ const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
688
+ const newVersion = newSnap.manifest.result.version;
689
+ if (!(0, utils_1.gtVersion)(newVersion, snap.version)) {
690
+ throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Snap "${snapId}@${snap.version}" is already installed. Couldn't update to a version inside requested "${newVersionRange}" range.`);
691
+ }
692
+ await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
693
+ version: newVersion,
694
+ checksum: newSnap.manifest.result.source.shasum,
695
+ });
696
+ const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
697
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_validateSnapPermissions).call(this, processedPermissions);
698
+ const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
699
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
685
700
  permissions: newPermissions,
686
- snapId,
687
701
  newVersion: newSnap.manifest.result.version,
688
702
  newPermissions,
689
703
  approvedPermissions,
690
704
  unusedPermissions,
691
- },
692
- }, true)), { permissions: approvedNewPermissions } = _b, requestData = __rest(_b, ["permissions"]);
693
- if (this.isRunning(snapId)) {
694
- await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
695
- }
696
- __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Update);
697
- __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
698
- origin,
699
- id: snapId,
700
- manifest: newSnap.manifest,
701
- files: newSnap.files,
702
- versionRange: newVersionRange,
703
- isUpdate: true,
704
- });
705
- const unusedPermissionsKeys = Object.keys(unusedPermissions);
706
- if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
707
- this.messagingSystem.call('PermissionController:revokePermissions', {
708
- [snapId]: unusedPermissionsKeys,
705
+ loading: false,
709
706
  });
710
- }
711
- if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedNewPermissions))) {
712
- this.messagingSystem.call('PermissionController:grantPermissions', {
713
- approvedPermissions: approvedNewPermissions,
714
- subject: { origin: snapId },
715
- requestData,
707
+ const { permissions: approvedNewPermissions, ...requestData } = (await pendingApproval.promise);
708
+ pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
709
+ origin,
710
+ snapId,
711
+ type: exports.SNAP_APPROVAL_RESULT,
716
712
  });
713
+ if (this.isRunning(snapId)) {
714
+ await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
715
+ }
716
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Update);
717
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
718
+ origin,
719
+ id: snapId,
720
+ manifest: newSnap.manifest,
721
+ files: newSnap.files,
722
+ versionRange: newVersionRange,
723
+ isUpdate: true,
724
+ });
725
+ const unusedPermissionsKeys = Object.keys(unusedPermissions);
726
+ if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
727
+ this.messagingSystem.call('PermissionController:revokePermissions', {
728
+ [snapId]: unusedPermissionsKeys,
729
+ });
730
+ }
731
+ if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedNewPermissions))) {
732
+ this.messagingSystem.call('PermissionController:grantPermissions', {
733
+ approvedPermissions: approvedNewPermissions,
734
+ subject: { origin: snapId },
735
+ requestData,
736
+ });
737
+ }
738
+ const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
739
+ if (rollbackSnapshot !== undefined) {
740
+ rollbackSnapshot.permissions.revoked = unusedPermissions;
741
+ rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
742
+ rollbackSnapshot.permissions.requestData = requestData;
743
+ }
744
+ const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(newSnap.manifest.result.source.location.npm.filePath);
745
+ const sourceCode = newSnap.files
746
+ .find((file) => file.path === normalizedSourcePath)
747
+ ?.toString();
748
+ (0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
749
+ try {
750
+ await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
751
+ }
752
+ catch {
753
+ throw new Error(`Snap ${snapId} crashed with updated source code.`);
754
+ }
755
+ const truncatedSnap = this.getTruncatedExpect(snapId);
756
+ this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
757
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, { loading: false });
758
+ return truncatedSnap;
717
759
  }
718
- const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
719
- if (rollbackSnapshot !== undefined) {
720
- rollbackSnapshot.permissions.revoked = unusedPermissions;
721
- rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
722
- rollbackSnapshot.permissions.requestData = requestData;
723
- }
724
- const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(newSnap.manifest.result.source.location.npm.filePath);
725
- const sourceCode = (_a = newSnap.files
726
- .find((file) => file.path === normalizedSourcePath)) === null || _a === void 0 ? void 0 : _a.toString();
727
- (0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
728
- try {
729
- await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
730
- }
731
- catch (_c) {
732
- throw new Error(`Snap ${snapId} crashed with updated source code.`);
760
+ catch (error) {
761
+ (0, snaps_utils_1.logError)(`Error when updating snap,`, error);
762
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
763
+ loading: false,
764
+ error: error instanceof Error ? error.message : error.toString(),
765
+ });
766
+ throw error;
733
767
  }
734
- const truncatedSnap = this.getTruncatedExpect(snapId);
735
- this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
736
- return truncatedSnap;
737
768
  }
738
769
  /**
739
770
  * Get metadata for the given snap ID.
@@ -751,36 +782,23 @@ class SnapController extends base_controller_1.BaseControllerV2 {
751
782
  *
752
783
  * This function is not hash private yet because of tests.
753
784
  *
754
- * @param origin - The origin of the install request.
755
785
  * @param snapId - The id of the Snap.
786
+ * @param pendingApproval - Pending approval to update.
756
787
  * @returns The snap's approvedPermissions.
757
788
  */
758
- async authorize(origin, snapId) {
789
+ async authorize(snapId, pendingApproval) {
759
790
  (0, logging_1.log)(`Authorizing snap: ${snapId}`);
760
791
  const snapsState = this.state.snaps;
761
792
  const snap = snapsState[snapId];
762
793
  const { initialPermissions } = snap;
763
794
  try {
764
795
  const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, initialPermissions);
765
- const excludedPermissionErrors = Object.keys(processedPermissions).reduce((errors, permission) => {
766
- if ((0, utils_1.hasProperty)(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f"), permission)) {
767
- errors.push(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f")[permission]);
768
- }
769
- return errors;
770
- }, []);
771
- (0, utils_1.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
772
- const id = (0, nanoid_1.nanoid)();
773
- const _a = (await this.messagingSystem.call('ApprovalController:addRequest', {
774
- origin,
775
- id,
776
- type: exports.SNAP_APPROVAL_INSTALL,
777
- requestData: {
778
- // Mirror previous installation metadata
779
- metadata: { id, origin: snapId, dappOrigin: origin },
780
- permissions: processedPermissions,
781
- snapId,
782
- },
783
- }, true)), { permissions: approvedPermissions } = _a, requestData = __rest(_a, ["permissions"]);
796
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_validateSnapPermissions).call(this, processedPermissions);
797
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
798
+ loading: false,
799
+ permissions: processedPermissions,
800
+ });
801
+ const { permissions: approvedPermissions, ...requestData } = (await pendingApproval.promise);
784
802
  if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedPermissions))) {
785
803
  this.messagingSystem.call('PermissionController:grantPermissions', {
786
804
  approvedPermissions,
@@ -823,9 +841,9 @@ class SnapController extends base_controller_1.BaseControllerV2 {
823
841
  }
824
842
  if (permissionName === endowments_1.SnapEndowments.Rpc) {
825
843
  const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
826
- const isSnap = (subject === null || subject === void 0 ? void 0 : subject.subjectType) === subject_metadata_controller_1.SubjectType.Snap;
844
+ const isSnap = subject?.subjectType === subject_metadata_controller_1.SubjectType.Snap;
827
845
  const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
828
- const rpcPermission = permissions === null || permissions === void 0 ? void 0 : permissions[endowments_1.SnapEndowments.Rpc];
846
+ const rpcPermission = permissions?.[endowments_1.SnapEndowments.Rpc];
829
847
  (0, utils_1.assert)(rpcPermission);
830
848
  const origins = (0, rpc_1.getRpcCaveatOrigins)(rpcPermission);
831
849
  (0, utils_1.assert)(origins);
@@ -951,13 +969,12 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
951
969
  });
952
970
  this.messagingSystem.publish(`${exports.controllerName}:snapUnblocked`, snapId);
953
971
  }, _SnapController_assertIsInstallAllowed = async function _SnapController_assertIsInstallAllowed(snapId, snapInfo) {
954
- var _a, _b;
955
972
  const results = await __classPrivateFieldGet(this, _SnapController_registry, "f").get({
956
973
  [snapId]: snapInfo,
957
974
  });
958
975
  const result = results[snapId];
959
976
  if (result.status === registry_1.SnapsRegistryStatus.Blocked) {
960
- throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${(_b = (_a = result.reason) === null || _a === void 0 ? void 0 : _a.explanation) !== null && _b !== void 0 ? _b : ''}`);
977
+ throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${result.reason?.explanation ?? ''}`);
961
978
  }
962
979
  else if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").requireAllowlist &&
963
980
  result.status !== registry_1.SnapsRegistryStatus.Verified) {
@@ -989,18 +1006,53 @@ async function _SnapController_terminateSnap(snapId) {
989
1006
  await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
990
1007
  this.messagingSystem.publish('SnapController:snapTerminated', this.getTruncatedExpect(snapId));
991
1008
  }, _SnapController_removeSnapFromSubjects = function _SnapController_removeSnapFromSubjects(snapId) {
992
- var _a, _b, _c, _d;
993
1009
  const subjects = this.messagingSystem.call('PermissionController:getSubjectNames');
994
1010
  for (const subject of subjects) {
995
1011
  const subjectPermissions = this.messagingSystem.call('PermissionController:getPermissions', subject);
996
- const snapIdsCaveat = ((_c = (_b = (_a = subjectPermissions === null || subjectPermissions === void 0 ? void 0 : subjectPermissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]) === null || _a === void 0 ? void 0 : _a.caveats) === null || _b === void 0 ? void 0 : _b.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)) !== null && _c !== void 0 ? _c : {});
997
- const caveatHasSnap = Boolean((_d = snapIdsCaveat.value) === null || _d === void 0 ? void 0 : _d[snapId]);
1012
+ const snapIdsCaveat = (subjectPermissions?.[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds) ??
1013
+ {});
1014
+ const caveatHasSnap = Boolean(snapIdsCaveat.value?.[snapId]);
998
1015
  if (caveatHasSnap) {
999
- const newCaveatValue = Object.assign({}, snapIdsCaveat.value);
1016
+ const newCaveatValue = {
1017
+ ...snapIdsCaveat.value,
1018
+ };
1000
1019
  delete newCaveatValue[snapId];
1001
- this.messagingSystem.call('PermissionController:updateCaveat', subject, rpc_methods_1.WALLET_SNAP_PERMISSION_KEY, snaps_utils_1.SnapCaveatType.SnapIds, newCaveatValue);
1020
+ if (Object.keys(newCaveatValue).length > 0) {
1021
+ this.messagingSystem.call('PermissionController:updateCaveat', subject, rpc_methods_1.WALLET_SNAP_PERMISSION_KEY, snaps_utils_1.SnapCaveatType.SnapIds, newCaveatValue);
1022
+ }
1023
+ else {
1024
+ this.messagingSystem.call('PermissionController:revokePermissions', {
1025
+ [subject]: [rpc_methods_1.WALLET_SNAP_PERMISSION_KEY],
1026
+ });
1027
+ }
1002
1028
  }
1003
1029
  }
1030
+ }, _SnapController_createApproval = function _SnapController_createApproval({ origin, snapId, type, }) {
1031
+ const id = (0, nanoid_1.nanoid)();
1032
+ const promise = this.messagingSystem.call('ApprovalController:addRequest', {
1033
+ origin,
1034
+ id,
1035
+ type,
1036
+ requestData: {
1037
+ // Mirror previous installation metadata
1038
+ metadata: { id, origin: snapId, dappOrigin: origin },
1039
+ snapId,
1040
+ },
1041
+ requestState: {
1042
+ loading: true,
1043
+ },
1044
+ }, true);
1045
+ return { id, promise };
1046
+ }, _SnapController_updateApproval = function _SnapController_updateApproval(id, requestState) {
1047
+ try {
1048
+ this.messagingSystem.call('ApprovalController:updateRequestState', {
1049
+ id,
1050
+ requestState,
1051
+ });
1052
+ }
1053
+ catch {
1054
+ // Do nothing
1055
+ }
1004
1056
  }, _SnapController_add =
1005
1057
  /**
1006
1058
  * Returns a promise representing the complete installation of the requested snap.
@@ -1013,7 +1065,6 @@ async function _SnapController_terminateSnap(snapId) {
1013
1065
  */
1014
1066
  async function _SnapController_add(args) {
1015
1067
  const { id: snapId, location } = args;
1016
- (0, snaps_utils_1.validateSnapId)(snapId);
1017
1068
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snapId, { sourceCode: null, state: null });
1018
1069
  const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
1019
1070
  if (!runtime.installPromise) {
@@ -1026,7 +1077,11 @@ async function _SnapController_add(args) {
1026
1077
  version: fetchedSnap.manifest.result.version,
1027
1078
  checksum: fetchedSnap.manifest.result.source.shasum,
1028
1079
  });
1029
- return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, Object.assign(Object.assign(Object.assign({}, args), fetchedSnap), { id: snapId }));
1080
+ return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
1081
+ ...args,
1082
+ ...fetchedSnap,
1083
+ id: snapId,
1084
+ });
1030
1085
  })();
1031
1086
  }
1032
1087
  try {
@@ -1044,7 +1099,10 @@ async function _SnapController_add(args) {
1044
1099
  throw new Error(`Snap "${snapId}" is already started.`);
1045
1100
  }
1046
1101
  try {
1047
- const result = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_executeWithTimeout).call(this, snapId, this.messagingSystem.call('ExecutionService:executeSnap', Object.assign(Object.assign({}, snapData), { endowments: await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getEndowments).call(this, snapId) })));
1102
+ const result = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_executeWithTimeout).call(this, snapId, this.messagingSystem.call('ExecutionService:executeSnap', {
1103
+ ...snapData,
1104
+ endowments: await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getEndowments).call(this, snapId),
1105
+ }));
1048
1106
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Start);
1049
1107
  return result;
1050
1108
  }
@@ -1091,7 +1149,6 @@ async function _SnapController_getEndowments(snapId) {
1091
1149
  }
1092
1150
  return dedupedEndowments;
1093
1151
  }, _SnapController_set = function _SnapController_set(args) {
1094
- var _a, _b;
1095
1152
  const { id: snapId, origin, manifest, files, versionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION, isUpdate = false, } = args;
1096
1153
  (0, snaps_utils_1.assertIsSnapManifest)(manifest.result);
1097
1154
  const { version } = manifest.result;
@@ -1101,15 +1158,16 @@ async function _SnapController_getEndowments(snapId) {
1101
1158
  const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(manifest.result.source.location.npm.filePath);
1102
1159
  const { iconPath } = manifest.result.source.location.npm;
1103
1160
  const normalizedIconPath = iconPath && (0, snaps_utils_1.normalizeRelative)(iconPath);
1104
- const sourceCode = (_a = files
1105
- .find((file) => file.path === normalizedSourcePath)) === null || _a === void 0 ? void 0 : _a.toString();
1161
+ const sourceCode = files
1162
+ .find((file) => file.path === normalizedSourcePath)
1163
+ ?.toString();
1106
1164
  const svgIcon = normalizedIconPath
1107
1165
  ? files.find((file) => file.path === normalizedIconPath)
1108
1166
  : undefined;
1109
1167
  (0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
1110
1168
  const snapsState = this.state.snaps;
1111
1169
  const existingSnap = snapsState[snapId];
1112
- const previousVersionHistory = (_b = existingSnap === null || existingSnap === void 0 ? void 0 : existingSnap.versionHistory) !== null && _b !== void 0 ? _b : [];
1170
+ const previousVersionHistory = existingSnap?.versionHistory ?? [];
1113
1171
  const versionHistory = [
1114
1172
  ...previousVersionHistory,
1115
1173
  {
@@ -1118,11 +1176,20 @@ async function _SnapController_getEndowments(snapId) {
1118
1176
  origin,
1119
1177
  },
1120
1178
  ];
1121
- const snap = Object.assign(Object.assign({}, existingSnap), {
1179
+ const snap = {
1180
+ // Restore relevant snap state if it exists
1181
+ ...existingSnap,
1122
1182
  // Note that the snap will be unblocked and enabled, regardless of its
1123
1183
  // previous state.
1124
- blocked: false, enabled: true, id: snapId, initialPermissions: manifest.result.initialPermissions, manifest: manifest.result, status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial, version,
1125
- versionHistory });
1184
+ blocked: false,
1185
+ enabled: true,
1186
+ id: snapId,
1187
+ initialPermissions: manifest.result.initialPermissions,
1188
+ manifest: manifest.result,
1189
+ status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial,
1190
+ version,
1191
+ versionHistory,
1192
+ };
1126
1193
  // If the snap was blocked, it isn't any longer
1127
1194
  delete snap.blockInformation;
1128
1195
  // store the snap back in state
@@ -1139,8 +1206,8 @@ async function _SnapController_getEndowments(snapId) {
1139
1206
  }
1140
1207
  const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
1141
1208
  runtime.sourceCode = sourceCode;
1142
- this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon === null || svgIcon === void 0 ? void 0 : svgIcon.toString());
1143
- return Object.assign(Object.assign({}, snap), { sourceCode });
1209
+ this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon?.toString());
1210
+ return { ...snap, sourceCode };
1144
1211
  }, _SnapController_fetchSnap =
1145
1212
  /**
1146
1213
  * Fetches the manifest and source code of a snap.
@@ -1171,7 +1238,7 @@ async function _SnapController_fetchSnap(snapId, location) {
1171
1238
  throw new Error(`Failed to fetch Snap "${snapId}": ${message}.`);
1172
1239
  }
1173
1240
  }, _SnapController_processSnapPermissions = function _SnapController_processSnapPermissions(initialPermissions) {
1174
- return (0, snaps_utils_1.fromEntries)(Object.entries(initialPermissions).map(([initialPermission, value]) => {
1241
+ return Object.fromEntries(Object.entries(initialPermissions).map(([initialPermission, value]) => {
1175
1242
  if ((0, utils_1.hasProperty)(rpc_methods_1.caveatMappers, initialPermission)) {
1176
1243
  return [initialPermission, rpc_methods_1.caveatMappers[initialPermission](value)];
1177
1244
  }
@@ -1187,6 +1254,14 @@ async function _SnapController_fetchSnap(snapId, location) {
1187
1254
  value,
1188
1255
  ];
1189
1256
  }));
1257
+ }, _SnapController_validateSnapPermissions = function _SnapController_validateSnapPermissions(processedPermissions) {
1258
+ const excludedPermissionErrors = Object.keys(processedPermissions).reduce((errors, permission) => {
1259
+ if ((0, utils_1.hasProperty)(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f"), permission)) {
1260
+ errors.push(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f")[permission]);
1261
+ }
1262
+ return errors;
1263
+ }, []);
1264
+ (0, utils_1.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
1190
1265
  }, _SnapController_getRpcRequestHandler = function _SnapController_getRpcRequestHandler(snapId) {
1191
1266
  const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
1192
1267
  const existingHandler = runtime.rpcHandler;
@@ -1227,7 +1302,7 @@ async function _SnapController_fetchSnap(snapId, location) {
1227
1302
  }
1228
1303
  let _request = request;
1229
1304
  if (!(0, utils_1.hasProperty)(request, 'jsonrpc')) {
1230
- _request = Object.assign(Object.assign({}, request), { jsonrpc: '2.0' });
1305
+ _request = { ...request, jsonrpc: '2.0' };
1231
1306
  }
1232
1307
  else if (request.jsonrpc !== '2.0') {
1233
1308
  throw eth_rpc_errors_1.ethErrors.rpc.invalidRequest({
@@ -1269,7 +1344,7 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
1269
1344
  (0, snaps_utils_1.logWarning)(`${endowments_1.SnapEndowments.LongRunning} will soon be deprecated. For more information please see https://github.com/MetaMask/snaps-monorepo/issues/945.`);
1270
1345
  return promise;
1271
1346
  }
1272
- const result = await (0, utils_2.withTimeout)(promise, timer !== null && timer !== void 0 ? timer : this.maxRequestTime);
1347
+ const result = await (0, utils_2.withTimeout)(promise, timer ?? this.maxRequestTime);
1273
1348
  if (result === utils_2.hasTimedOut) {
1274
1349
  throw new Error('The request timed out.');
1275
1350
  }
@@ -1310,14 +1385,13 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
1310
1385
  * @throws {@link Error}. If a snapshot does not exist.
1311
1386
  */
1312
1387
  async function _SnapController_rollbackSnap(snapId) {
1313
- var _a;
1314
1388
  const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
1315
1389
  if (!rollbackSnapshot) {
1316
1390
  throw new Error('A snapshot does not exist for this snap.');
1317
1391
  }
1318
1392
  await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
1319
1393
  const { statePatches, sourceCode, permissions } = rollbackSnapshot;
1320
- if (statePatches === null || statePatches === void 0 ? void 0 : statePatches.length) {
1394
+ if (statePatches?.length) {
1321
1395
  this.applyPatches(statePatches);
1322
1396
  }
1323
1397
  if (sourceCode) {
@@ -1331,7 +1405,7 @@ async function _SnapController_rollbackSnap(snapId) {
1331
1405
  requestData: permissions.requestData,
1332
1406
  });
1333
1407
  }
1334
- if ((_a = permissions.granted) === null || _a === void 0 ? void 0 : _a.length) {
1408
+ if (permissions.granted?.length) {
1335
1409
  this.messagingSystem.call('PermissionController:revokePermissions', {
1336
1410
  [snapId]: permissions.granted,
1337
1411
  });
@@ -1357,7 +1431,6 @@ async function _SnapController_rollbackSnaps(snapIds) {
1357
1431
  (0, utils_1.assert)(runtime !== undefined, new Error(`Snap "${snapId}" runtime data not found`));
1358
1432
  return runtime;
1359
1433
  }, _SnapController_setupRuntime = function _SnapController_setupRuntime(snapId, data) {
1360
- var _a;
1361
1434
  if (this.snapsRuntimeData.has(snapId)) {
1362
1435
  return;
1363
1436
  }
@@ -1365,13 +1438,22 @@ async function _SnapController_rollbackSnaps(snapIds) {
1365
1438
  const interpreter = (0, fsm_1.interpret)(__classPrivateFieldGet(this, _SnapController_statusMachine, "f"));
1366
1439
  interpreter.start({
1367
1440
  context: { snapId },
1368
- value: (_a = snap === null || snap === void 0 ? void 0 : snap.status) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial,
1441
+ value: snap?.status ??
1442
+ __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial,
1369
1443
  });
1370
1444
  (0, fsm_2.forceStrict)(interpreter);
1371
- this.snapsRuntimeData.set(snapId, Object.assign({ lastRequest: null, rpcHandler: null, installPromise: null, activeReferences: 0, pendingInboundRequests: [], pendingOutboundRequests: 0, interpreter }, data));
1445
+ this.snapsRuntimeData.set(snapId, {
1446
+ lastRequest: null,
1447
+ rpcHandler: null,
1448
+ installPromise: null,
1449
+ activeReferences: 0,
1450
+ pendingInboundRequests: [],
1451
+ pendingOutboundRequests: 0,
1452
+ interpreter,
1453
+ ...data,
1454
+ });
1372
1455
  }, _SnapController_calculatePermissionsChange = function _SnapController_calculatePermissionsChange(snapId, desiredPermissionsSet) {
1373
- var _a;
1374
- const oldPermissions = (_a = this.messagingSystem.call('PermissionController:getPermissions', snapId)) !== null && _a !== void 0 ? _a : {};
1456
+ const oldPermissions = this.messagingSystem.call('PermissionController:getPermissions', snapId) ?? {};
1375
1457
  const newPermissions = (0, utils_2.setDiff)(desiredPermissionsSet, oldPermissions);
1376
1458
  // TODO(ritave): The assumption that these are unused only holds so long as we do not
1377
1459
  // permit dynamic permission requests.