@metamask-previews/gator-permissions-controller 5.0.2-preview-4f4c98e → 5.0.2-preview-eb263b0ee

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 (187) hide show
  1. package/CHANGELOG.md +0 -4
  2. package/dist/GatorPermissionsController-method-action-types.cjs +7 -0
  3. package/dist/GatorPermissionsController-method-action-types.cjs.map +1 -0
  4. package/dist/{GatorPermissionsController-method-action-types.d.ts → GatorPermissionsController-method-action-types.d.cts} +2 -2
  5. package/dist/GatorPermissionsController-method-action-types.d.cts.map +1 -0
  6. package/dist/GatorPermissionsController-method-action-types.d.mts +118 -0
  7. package/dist/GatorPermissionsController-method-action-types.d.mts.map +1 -0
  8. package/dist/{GatorPermissionsController-method-action-types.js → GatorPermissionsController-method-action-types.mjs} +1 -1
  9. package/dist/GatorPermissionsController-method-action-types.mjs.map +1 -0
  10. package/dist/GatorPermissionsController.cjs +589 -0
  11. package/dist/GatorPermissionsController.cjs.map +1 -0
  12. package/dist/{GatorPermissionsController.d.ts → GatorPermissionsController.d.cts} +12 -12
  13. package/dist/GatorPermissionsController.d.cts.map +1 -0
  14. package/dist/GatorPermissionsController.d.mts +219 -0
  15. package/dist/GatorPermissionsController.d.mts.map +1 -0
  16. package/dist/{GatorPermissionsController.js → GatorPermissionsController.mjs} +12 -12
  17. package/dist/GatorPermissionsController.mjs.map +1 -0
  18. package/dist/constants.cjs +29 -0
  19. package/dist/constants.cjs.map +1 -0
  20. package/dist/{constants.d.ts → constants.d.cts} +4 -4
  21. package/dist/constants.d.cts.map +1 -0
  22. package/dist/constants.d.mts +26 -0
  23. package/dist/constants.d.mts.map +1 -0
  24. package/dist/{constants.js → constants.mjs} +1 -1
  25. package/dist/constants.mjs.map +1 -0
  26. package/dist/decodePermission/decodePermission.cjs +110 -0
  27. package/dist/decodePermission/decodePermission.cjs.map +1 -0
  28. package/dist/decodePermission/{decodePermission.d.ts → decodePermission.d.cts} +3 -3
  29. package/dist/decodePermission/decodePermission.d.cts.map +1 -0
  30. package/dist/decodePermission/decodePermission.d.mts +72 -0
  31. package/dist/decodePermission/decodePermission.d.mts.map +1 -0
  32. package/dist/decodePermission/{decodePermission.js → decodePermission.mjs} +3 -3
  33. package/dist/decodePermission/decodePermission.mjs.map +1 -0
  34. package/dist/decodePermission/decoders/index.cjs +26 -0
  35. package/dist/decodePermission/decoders/index.cjs.map +1 -0
  36. package/dist/decodePermission/decoders/{index.d.ts → index.d.cts} +3 -3
  37. package/dist/decodePermission/decoders/index.d.cts.map +1 -0
  38. package/dist/decodePermission/decoders/index.d.mts +20 -0
  39. package/dist/decodePermission/decoders/index.d.mts.map +1 -0
  40. package/dist/decodePermission/decoders/{index.js → index.mjs} +3 -3
  41. package/dist/decodePermission/decoders/index.mjs.map +1 -0
  42. package/dist/decodePermission/decoders/makePermissionDecoder.cjs +108 -0
  43. package/dist/decodePermission/decoders/makePermissionDecoder.cjs.map +1 -0
  44. package/dist/decodePermission/decoders/{makePermissionDecoder.d.ts → makePermissionDecoder.d.cts} +3 -3
  45. package/dist/decodePermission/decoders/makePermissionDecoder.d.cts.map +1 -0
  46. package/dist/decodePermission/decoders/makePermissionDecoder.d.mts +46 -0
  47. package/dist/decodePermission/decoders/makePermissionDecoder.d.mts.map +1 -0
  48. package/dist/decodePermission/decoders/{makePermissionDecoder.js → makePermissionDecoder.mjs} +4 -4
  49. package/dist/decodePermission/decoders/makePermissionDecoder.mjs.map +1 -0
  50. package/dist/decodePermission/enforcerAddresses.cjs +39 -0
  51. package/dist/decodePermission/enforcerAddresses.cjs.map +1 -0
  52. package/dist/decodePermission/{enforcerAddresses.d.ts → enforcerAddresses.d.cts} +3 -3
  53. package/dist/decodePermission/enforcerAddresses.d.cts.map +1 -0
  54. package/dist/decodePermission/enforcerAddresses.d.mts +13 -0
  55. package/dist/decodePermission/enforcerAddresses.d.mts.map +1 -0
  56. package/dist/decodePermission/{enforcerAddresses.js → enforcerAddresses.mjs} +4 -4
  57. package/dist/decodePermission/enforcerAddresses.mjs.map +1 -0
  58. package/dist/decodePermission/index.cjs +10 -0
  59. package/dist/decodePermission/index.cjs.map +1 -0
  60. package/dist/decodePermission/{index.d.ts → index.d.cts} +4 -4
  61. package/dist/decodePermission/index.d.cts.map +1 -0
  62. package/dist/decodePermission/index.d.mts +4 -0
  63. package/dist/decodePermission/index.d.mts.map +1 -0
  64. package/dist/decodePermission/index.mjs +3 -0
  65. package/dist/decodePermission/index.mjs.map +1 -0
  66. package/dist/decodePermission/types.cjs +3 -0
  67. package/dist/decodePermission/types.cjs.map +1 -0
  68. package/dist/decodePermission/{types.d.ts → types.d.cts} +4 -4
  69. package/dist/decodePermission/types.d.cts.map +1 -0
  70. package/dist/decodePermission/types.d.mts +64 -0
  71. package/dist/decodePermission/types.d.mts.map +1 -0
  72. package/dist/decodePermission/types.mjs +2 -0
  73. package/dist/decodePermission/types.mjs.map +1 -0
  74. package/dist/decodePermission/utils.cjs +125 -0
  75. package/dist/decodePermission/utils.cjs.map +1 -0
  76. package/dist/decodePermission/{utils.d.ts → utils.d.cts} +3 -3
  77. package/dist/decodePermission/utils.d.cts.map +1 -0
  78. package/dist/decodePermission/utils.d.mts +68 -0
  79. package/dist/decodePermission/utils.d.mts.map +1 -0
  80. package/dist/decodePermission/{utils.js → utils.mjs} +2 -2
  81. package/dist/decodePermission/utils.mjs.map +1 -0
  82. package/dist/errors.cjs +54 -0
  83. package/dist/errors.cjs.map +1 -0
  84. package/dist/{errors.d.ts → errors.d.cts} +3 -3
  85. package/dist/errors.d.cts.map +1 -0
  86. package/dist/errors.d.mts +39 -0
  87. package/dist/errors.d.mts.map +1 -0
  88. package/dist/{errors.js → errors.mjs} +2 -2
  89. package/dist/errors.mjs.map +1 -0
  90. package/dist/index.cjs +14 -0
  91. package/dist/index.cjs.map +1 -0
  92. package/dist/{index.d.ts → index.d.cts} +10 -10
  93. package/dist/index.d.cts.map +1 -0
  94. package/dist/index.d.mts +10 -0
  95. package/dist/index.d.mts.map +1 -0
  96. package/dist/index.mjs +3 -0
  97. package/dist/index.mjs.map +1 -0
  98. package/dist/logger.cjs +10 -0
  99. package/dist/logger.cjs.map +1 -0
  100. package/dist/{logger.d.ts → logger.d.cts} +3 -2
  101. package/dist/logger.d.cts.map +1 -0
  102. package/dist/logger.d.mts +7 -0
  103. package/dist/logger.d.mts.map +1 -0
  104. package/dist/{logger.js → logger.mjs} +2 -2
  105. package/dist/logger.mjs.map +1 -0
  106. package/dist/payeeRule.cjs +3 -0
  107. package/dist/payeeRule.cjs.map +1 -0
  108. package/dist/{payeeRule.d.ts → payeeRule.d.cts} +2 -2
  109. package/dist/payeeRule.d.cts.map +1 -0
  110. package/dist/payeeRule.d.mts +12 -0
  111. package/dist/payeeRule.d.mts.map +1 -0
  112. package/dist/payeeRule.mjs +2 -0
  113. package/dist/payeeRule.mjs.map +1 -0
  114. package/dist/permissionOnChainStatus.cjs +140 -0
  115. package/dist/permissionOnChainStatus.cjs.map +1 -0
  116. package/dist/{permissionOnChainStatus.d.ts → permissionOnChainStatus.d.cts} +5 -5
  117. package/dist/permissionOnChainStatus.d.cts.map +1 -0
  118. package/dist/permissionOnChainStatus.d.mts +73 -0
  119. package/dist/permissionOnChainStatus.d.mts.map +1 -0
  120. package/dist/{permissionOnChainStatus.js → permissionOnChainStatus.mjs} +7 -7
  121. package/dist/permissionOnChainStatus.mjs.map +1 -0
  122. package/dist/redeemerRule.cjs +3 -0
  123. package/dist/redeemerRule.cjs.map +1 -0
  124. package/dist/{redeemerRule.d.ts → redeemerRule.d.cts} +2 -2
  125. package/dist/redeemerRule.d.cts.map +1 -0
  126. package/dist/redeemerRule.d.mts +12 -0
  127. package/dist/redeemerRule.d.mts.map +1 -0
  128. package/dist/redeemerRule.mjs +2 -0
  129. package/dist/redeemerRule.mjs.map +1 -0
  130. package/dist/types.cjs +28 -0
  131. package/dist/types.cjs.map +1 -0
  132. package/dist/{types.d.ts → types.d.cts} +4 -4
  133. package/dist/types.d.cts.map +1 -0
  134. package/dist/types.d.mts +161 -0
  135. package/dist/types.d.mts.map +1 -0
  136. package/dist/{types.js → types.mjs} +1 -1
  137. package/dist/types.mjs.map +1 -0
  138. package/dist/utils.cjs +41 -0
  139. package/dist/utils.cjs.map +1 -0
  140. package/dist/{utils.d.ts → utils.d.cts} +5 -5
  141. package/dist/utils.d.cts.map +1 -0
  142. package/dist/utils.d.mts +22 -0
  143. package/dist/utils.d.mts.map +1 -0
  144. package/dist/{utils.js → utils.mjs} +4 -4
  145. package/dist/utils.mjs.map +1 -0
  146. package/package.json +16 -12
  147. package/dist/GatorPermissionsController-method-action-types.d.ts.map +0 -1
  148. package/dist/GatorPermissionsController-method-action-types.js.map +0 -1
  149. package/dist/GatorPermissionsController.d.ts.map +0 -1
  150. package/dist/GatorPermissionsController.js.map +0 -1
  151. package/dist/constants.d.ts.map +0 -1
  152. package/dist/constants.js.map +0 -1
  153. package/dist/decodePermission/decodePermission.d.ts.map +0 -1
  154. package/dist/decodePermission/decodePermission.js.map +0 -1
  155. package/dist/decodePermission/decoders/index.d.ts.map +0 -1
  156. package/dist/decodePermission/decoders/index.js.map +0 -1
  157. package/dist/decodePermission/decoders/makePermissionDecoder.d.ts.map +0 -1
  158. package/dist/decodePermission/decoders/makePermissionDecoder.js.map +0 -1
  159. package/dist/decodePermission/enforcerAddresses.d.ts.map +0 -1
  160. package/dist/decodePermission/enforcerAddresses.js.map +0 -1
  161. package/dist/decodePermission/index.d.ts.map +0 -1
  162. package/dist/decodePermission/index.js +0 -3
  163. package/dist/decodePermission/index.js.map +0 -1
  164. package/dist/decodePermission/types.d.ts.map +0 -1
  165. package/dist/decodePermission/types.js +0 -2
  166. package/dist/decodePermission/types.js.map +0 -1
  167. package/dist/decodePermission/utils.d.ts.map +0 -1
  168. package/dist/decodePermission/utils.js.map +0 -1
  169. package/dist/errors.d.ts.map +0 -1
  170. package/dist/errors.js.map +0 -1
  171. package/dist/index.d.ts.map +0 -1
  172. package/dist/index.js +0 -3
  173. package/dist/index.js.map +0 -1
  174. package/dist/logger.d.ts.map +0 -1
  175. package/dist/logger.js.map +0 -1
  176. package/dist/payeeRule.d.ts.map +0 -1
  177. package/dist/payeeRule.js +0 -2
  178. package/dist/payeeRule.js.map +0 -1
  179. package/dist/permissionOnChainStatus.d.ts.map +0 -1
  180. package/dist/permissionOnChainStatus.js.map +0 -1
  181. package/dist/redeemerRule.d.ts.map +0 -1
  182. package/dist/redeemerRule.js +0 -2
  183. package/dist/redeemerRule.js.map +0 -1
  184. package/dist/types.d.ts.map +0 -1
  185. package/dist/types.js.map +0 -1
  186. package/dist/utils.d.ts.map +0 -1
  187. package/dist/utils.js.map +0 -1
@@ -0,0 +1,589 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
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
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _GatorPermissionsController_instances, _GatorPermissionsController_supportedPermissionTypes, _GatorPermissionsController_gatorPermissionsProviderSnapId, _GatorPermissionsController_maxSyncIntervalMs, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, _GatorPermissionsController_setIsFetchingGatorPermissions, _GatorPermissionsController_addPendingRevocationToState, _GatorPermissionsController_removePendingRevocationFromStateByTxId, _GatorPermissionsController_removePendingRevocationFromStateByPermissionContext, _GatorPermissionsController_buildPreviousStatusByContext, _GatorPermissionsController_getProviderForChainId, _GatorPermissionsController_updateGrantedPermissionsStatus, _GatorPermissionsController_storedPermissionToPermissionInfo, _GatorPermissionsController_storedPermissionsToPermissionInfoWithMetadata;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.GatorPermissionsController = void 0;
16
+ const base_controller_1 = require("@metamask/base-controller");
17
+ const snaps_utils_1 = require("@metamask/snaps-utils");
18
+ const transaction_controller_1 = require("@metamask/transaction-controller");
19
+ const index_js_1 = require("./decodePermission/decoders/index.cjs");
20
+ const enforcerAddresses_js_1 = require("./decodePermission/enforcerAddresses.cjs");
21
+ const index_js_2 = require("./decodePermission/index.cjs");
22
+ const errors_js_1 = require("./errors.cjs");
23
+ const logger_js_1 = require("./logger.cjs");
24
+ const permissionOnChainStatus_js_1 = require("./permissionOnChainStatus.cjs");
25
+ const types_js_1 = require("./types.cjs");
26
+ const utils_js_1 = require("./utils.cjs");
27
+ // === GENERAL ===
28
+ // Unique name for the controller
29
+ const controllerName = 'GatorPermissionsController';
30
+ const MESSENGER_EXPOSED_METHODS = [
31
+ 'fetchAndUpdateGatorPermissions',
32
+ 'initialize',
33
+ 'decodePermissionFromPermissionContextForOrigin',
34
+ 'submitRevocation',
35
+ 'addPendingRevocation',
36
+ 'submitDirectRevocation',
37
+ 'isPendingRevocation',
38
+ ];
39
+ // Default value for the gator permissions provider snap id
40
+ const defaultGatorPermissionsProviderSnapId = 'npm:@metamask/gator-permissions-snap';
41
+ const DEFAULT_MAX_SYNC_INTERVAL_MS = 30 * 24 * 60 * 60 * 1000; // 30 days in milliseconds
42
+ /**
43
+ * Timeout duration for pending revocations (2 hours in milliseconds).
44
+ * After this time, event listeners will be cleaned up to prevent memory leaks.
45
+ */
46
+ const PENDING_REVOCATION_TIMEOUT = 2 * 60 * 60 * 1000;
47
+ const gatorPermissionsControllerMetadata = {
48
+ grantedPermissions: {
49
+ includeInStateLogs: true,
50
+ persist: true,
51
+ includeInDebugSnapshot: false,
52
+ usedInUi: true,
53
+ },
54
+ isFetchingGatorPermissions: {
55
+ includeInStateLogs: true,
56
+ persist: false,
57
+ includeInDebugSnapshot: false,
58
+ usedInUi: true,
59
+ },
60
+ pendingRevocations: {
61
+ includeInStateLogs: true,
62
+ persist: false,
63
+ includeInDebugSnapshot: false,
64
+ usedInUi: true,
65
+ },
66
+ lastSyncedTimestamp: {
67
+ includeInStateLogs: true,
68
+ persist: true,
69
+ includeInDebugSnapshot: false,
70
+ usedInUi: false,
71
+ },
72
+ };
73
+ /**
74
+ * Creates initial controller state, merging defaults with optional partial state.
75
+ * Internal use only (e.g. constructor, tests).
76
+ *
77
+ * @param state - Optional partial state to merge with defaults.
78
+ * @returns Complete {@link GatorPermissionsController} state.
79
+ */
80
+ function createGatorPermissionsControllerState(state) {
81
+ return {
82
+ grantedPermissions: [],
83
+ pendingRevocations: [],
84
+ lastSyncedTimestamp: -1,
85
+ ...state,
86
+ // isFetchingGatorPermissions is _always_ false when the controller is created
87
+ isFetchingGatorPermissions: false,
88
+ };
89
+ }
90
+ /**
91
+ * Controller that manages gator permissions by reading from the gator permissions provider Snap.
92
+ */
93
+ class GatorPermissionsController extends base_controller_1.BaseController {
94
+ /**
95
+ * The Snap ID of the gator permissions provider.
96
+ *
97
+ * @returns The Snap ID of the gator permissions provider.
98
+ */
99
+ get gatorPermissionsProviderSnapId() {
100
+ return __classPrivateFieldGet(this, _GatorPermissionsController_gatorPermissionsProviderSnapId, "f");
101
+ }
102
+ /**
103
+ * Creates a GatorPermissionsController instance.
104
+ *
105
+ * @param args - The arguments to this function.
106
+ * @param args.messenger - Messenger used to communicate with other controllers.
107
+ * @param args.config - Configuration (supported permission types and optional Snap id).
108
+ * @param args.state - Optional partial state to merge with defaults.
109
+ */
110
+ constructor({ messenger, config, state, }) {
111
+ const initialState = createGatorPermissionsControllerState(state);
112
+ super({
113
+ name: controllerName,
114
+ metadata: gatorPermissionsControllerMetadata,
115
+ messenger,
116
+ state: initialState,
117
+ });
118
+ _GatorPermissionsController_instances.add(this);
119
+ _GatorPermissionsController_supportedPermissionTypes.set(this, void 0);
120
+ _GatorPermissionsController_gatorPermissionsProviderSnapId.set(this, void 0);
121
+ _GatorPermissionsController_maxSyncIntervalMs.set(this, void 0);
122
+ /**
123
+ * When a sync is in progress, holds the promise for that sync so concurrent
124
+ * callers receive the same promise. Cleared when the sync completes.
125
+ */
126
+ _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise.set(this, null);
127
+ __classPrivateFieldSet(this, _GatorPermissionsController_supportedPermissionTypes, config.supportedPermissionTypes, "f");
128
+ __classPrivateFieldSet(this, _GatorPermissionsController_gatorPermissionsProviderSnapId, config.gatorPermissionsProviderSnapId ??
129
+ defaultGatorPermissionsProviderSnapId, "f");
130
+ __classPrivateFieldSet(this, _GatorPermissionsController_maxSyncIntervalMs, config.maxSyncIntervalMs ?? DEFAULT_MAX_SYNC_INTERVAL_MS, "f");
131
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
132
+ }
133
+ /**
134
+ * Supported permission types this controller was configured with.
135
+ *
136
+ * @returns The supported permission types.
137
+ */
138
+ get supportedPermissionTypes() {
139
+ return __classPrivateFieldGet(this, _GatorPermissionsController_supportedPermissionTypes, "f");
140
+ }
141
+ /**
142
+ * Fetches granted permissions from the gator permissions provider Snap and updates state.
143
+ * If a sync is already in progress, returns the same promise. After the sync completes,
144
+ * the next call will perform a new sync.
145
+ *
146
+ * @returns A promise that resolves when the sync completes. All data is available via the controller's state.
147
+ * @throws {GatorPermissionsFetchError} If the gator permissions fetch fails.
148
+ */
149
+ fetchAndUpdateGatorPermissions() {
150
+ if (__classPrivateFieldGet(this, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, "f") !== null) {
151
+ return __classPrivateFieldGet(this, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, "f");
152
+ }
153
+ const performFetchAndUpdate = async () => {
154
+ try {
155
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_setIsFetchingGatorPermissions).call(this, true);
156
+ // Only ever fetch non-revoked permissions. Revoked permissions may be
157
+ // left in storage by the gator permissions snap, but we don't need to
158
+ // fetch them.
159
+ const params = { isRevoked: false };
160
+ const permissionsData = await (0, utils_js_1.executeSnapRpc)({
161
+ messenger: this.messenger,
162
+ snapId: __classPrivateFieldGet(this, _GatorPermissionsController_gatorPermissionsProviderSnapId, "f"),
163
+ method: types_js_1.GatorPermissionsSnapRpcMethod.PermissionProviderGetGrantedPermissions,
164
+ params,
165
+ });
166
+ const grantedPermissions = __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_storedPermissionsToPermissionInfoWithMetadata).call(this, permissionsData);
167
+ this.update((state) => {
168
+ state.grantedPermissions = grantedPermissions;
169
+ state.lastSyncedTimestamp = Date.now();
170
+ });
171
+ const grantedPermissionsWithStatus = await __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_updateGrantedPermissionsStatus).call(this, grantedPermissions);
172
+ this.update((state) => {
173
+ state.grantedPermissions = grantedPermissionsWithStatus;
174
+ });
175
+ }
176
+ catch (error) {
177
+ (0, logger_js_1.controllerLog)('Failed to fetch gator permissions', error);
178
+ throw new errors_js_1.GatorPermissionsFetchError({
179
+ message: 'Failed to fetch gator permissions',
180
+ cause: error,
181
+ });
182
+ }
183
+ finally {
184
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_setIsFetchingGatorPermissions).call(this, false);
185
+ __classPrivateFieldSet(this, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, null, "f");
186
+ }
187
+ };
188
+ __classPrivateFieldSet(this, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, performFetchAndUpdate(), "f");
189
+ return __classPrivateFieldGet(this, _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise, "f");
190
+ }
191
+ /**
192
+ * Initializes the controller. Call once after construction to ensure the
193
+ * controller is ready for use.
194
+ *
195
+ * @returns A promise that resolves when initialization is complete.
196
+ */
197
+ async initialize() {
198
+ const currentTime = Date.now();
199
+ const millisecondsSinceLastSync = currentTime - this.state.lastSyncedTimestamp;
200
+ // Sync only when we have no data or data is stale, to avoid excessive startup
201
+ // queries while still avoiding showing stale data while a refresh runs.
202
+ if (this.state.lastSyncedTimestamp === -1 ||
203
+ millisecondsSinceLastSync > __classPrivateFieldGet(this, _GatorPermissionsController_maxSyncIntervalMs, "f")) {
204
+ await this.fetchAndUpdateGatorPermissions();
205
+ }
206
+ }
207
+ /**
208
+ * Decodes a permission context into a structured permission for a specific origin.
209
+ *
210
+ * This method validates the caller origin, decodes the provided `permissionContext`
211
+ * into delegations, identifies the permission type from the caveat enforcers,
212
+ * extracts the permission-specific data and expiry, and reconstructs a
213
+ * {@link DecodedPermission} containing chainId, account addresses, to, type and data.
214
+ *
215
+ * @param args - The arguments to this function.
216
+ * @param args.origin - The caller's origin; must match the configured permissions provider Snap id.
217
+ * @param args.chainId - Numeric EIP-155 chain id used for resolving enforcer contracts and encoding.
218
+ * @param args.delegation - delegation representing the permission.
219
+ * @param args.metadata - metadata included in the request.
220
+ * @param args.metadata.justification - the justification as specified in the request metadata.
221
+ * @param args.metadata.origin - the origin as specified in the request metadata.
222
+ *
223
+ * @returns A decoded permission object suitable for UI consumption and follow-up actions.
224
+ * @throws If the origin is not allowed, the context cannot be decoded into exactly one delegation,
225
+ * the enforcers do not match any supported permission type, no candidate type validates
226
+ * the caveat terms, or more than one permission type successfully validates
227
+ * (ambiguous delegation).
228
+ */
229
+ decodePermissionFromPermissionContextForOrigin({ origin, chainId, delegation: { caveats, delegator, delegate, authority }, metadata: { justification, origin: specifiedOrigin }, }) {
230
+ if (origin !== __classPrivateFieldGet(this, _GatorPermissionsController_gatorPermissionsProviderSnapId, "f")) {
231
+ throw new errors_js_1.OriginNotAllowedError({ origin });
232
+ }
233
+ const deploymentContracts = enforcerAddresses_js_1.delegationContractsByChainId[chainId];
234
+ try {
235
+ if (!deploymentContracts) {
236
+ throw new Error(`Contracts not found for chainId: ${chainId}`);
237
+ }
238
+ const contracts = (0, enforcerAddresses_js_1.toEnforcerAddressesByName)(deploymentContracts);
239
+ const enforcers = caveats.map((caveat) => caveat.enforcer);
240
+ const permissionDecoders = (0, index_js_1.createPermissionDecodersForContracts)(contracts);
241
+ // Every decoder where enforcer addresses match; multiple types may share the
242
+ // same caveat pattern and are disambiguated by validateAndDecodePermission.
243
+ const matchingDecoders = (0, index_js_2.findDecodersWithMatchingCaveatAddresses)({
244
+ enforcers,
245
+ permissionDecoders,
246
+ });
247
+ const { decoder: { permissionType }, expiry, data, rules, } = (0, index_js_2.selectUniqueDecoderAndDecodedPermission)({
248
+ candidateDecoders: matchingDecoders,
249
+ caveats,
250
+ });
251
+ const permission = (0, index_js_2.reconstructDecodedPermission)({
252
+ chainId,
253
+ permissionType,
254
+ delegator,
255
+ delegate,
256
+ authority,
257
+ expiry,
258
+ data,
259
+ justification,
260
+ rules,
261
+ specifiedOrigin,
262
+ });
263
+ return permission;
264
+ }
265
+ catch (error) {
266
+ throw new errors_js_1.PermissionDecodingError({
267
+ cause: error,
268
+ });
269
+ }
270
+ }
271
+ /**
272
+ * Submits a revocation to the gator permissions provider snap.
273
+ *
274
+ * @param revocationParams - The revocation parameters containing the permission context.
275
+ * @returns A promise that resolves when the revocation is submitted successfully.
276
+ * @throws {GatorPermissionsProviderError} If the snap request fails.
277
+ */
278
+ async submitRevocation(revocationParams) {
279
+ (0, logger_js_1.controllerLog)('submitRevocation method called', {
280
+ permissionContext: revocationParams.permissionContext,
281
+ });
282
+ const snapRequest = {
283
+ snapId: __classPrivateFieldGet(this, _GatorPermissionsController_gatorPermissionsProviderSnapId, "f"),
284
+ origin: 'metamask',
285
+ handler: snaps_utils_1.HandlerType.OnRpcRequest,
286
+ request: {
287
+ jsonrpc: '2.0',
288
+ method: types_js_1.GatorPermissionsSnapRpcMethod.PermissionProviderSubmitRevocation,
289
+ params: revocationParams,
290
+ },
291
+ };
292
+ try {
293
+ const result = await this.messenger.call('SnapController:handleRequest', snapRequest);
294
+ // Refresh list first (permission removed from list)
295
+ await this.fetchAndUpdateGatorPermissions();
296
+ (0, logger_js_1.controllerLog)('Successfully submitted revocation', {
297
+ permissionContext: revocationParams.permissionContext,
298
+ result,
299
+ });
300
+ }
301
+ catch (error) {
302
+ // If it's a GatorPermissionsFetchError, revocation succeeded but refresh failed
303
+ if (error instanceof errors_js_1.GatorPermissionsFetchError) {
304
+ (0, logger_js_1.controllerLog)('Revocation submitted successfully but failed to refresh permissions list', {
305
+ error,
306
+ permissionContext: revocationParams.permissionContext,
307
+ });
308
+ // Wrap with a more specific message indicating revocation succeeded
309
+ throw new errors_js_1.GatorPermissionsFetchError({
310
+ message: 'Failed to refresh permissions list after successful revocation',
311
+ cause: error,
312
+ });
313
+ }
314
+ // Otherwise, revocation failed - wrap in provider error
315
+ (0, logger_js_1.controllerLog)('Failed to submit revocation', {
316
+ error,
317
+ permissionContext: revocationParams.permissionContext,
318
+ });
319
+ throw new errors_js_1.GatorPermissionsProviderError({
320
+ method: types_js_1.GatorPermissionsSnapRpcMethod.PermissionProviderSubmitRevocation,
321
+ cause: error,
322
+ });
323
+ }
324
+ finally {
325
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_removePendingRevocationFromStateByPermissionContext).call(this, revocationParams.permissionContext);
326
+ }
327
+ }
328
+ /**
329
+ * Adds a pending revocation that will be submitted once the transaction is confirmed.
330
+ *
331
+ * This method sets up listeners for the user's approval/rejection decision and
332
+ * terminal transaction states (confirmed, failed, dropped). The flow is:
333
+ * 1. Wait for user to approve or reject the transaction
334
+ * 2. If approved, add to pending revocations state
335
+ * 3. If rejected, cleanup without adding to state
336
+ * 4. If confirmed, submit the revocation
337
+ * 5. If failed or dropped, cleanup
338
+ *
339
+ * Includes a timeout safety net to prevent memory leaks if the transaction never
340
+ * reaches a terminal state.
341
+ *
342
+ * @param params - The pending revocation parameters.
343
+ * @returns A promise that resolves when the listener is set up.
344
+ */
345
+ async addPendingRevocation(params) {
346
+ const { txId, permissionContext } = params;
347
+ (0, logger_js_1.controllerLog)('addPendingRevocation method called', {
348
+ txId,
349
+ permissionContext,
350
+ });
351
+ // Track handlers and timeout for cleanup
352
+ const handlers = {
353
+ approved: undefined,
354
+ rejected: undefined,
355
+ confirmed: undefined,
356
+ failed: undefined,
357
+ dropped: undefined,
358
+ timeoutId: undefined,
359
+ };
360
+ // Helper to refresh permissions after transaction state change
361
+ const refreshPermissions = (context) => {
362
+ this.fetchAndUpdateGatorPermissions().catch((error) => {
363
+ (0, logger_js_1.controllerLog)(`Failed to refresh permissions after ${context}`, {
364
+ txId,
365
+ permissionContext,
366
+ error,
367
+ });
368
+ });
369
+ };
370
+ // Helper to unsubscribe from approval/rejection events after decision is made
371
+ const cleanupApprovalHandlers = () => {
372
+ if (handlers.approved) {
373
+ this.messenger.unsubscribe('TransactionController:transactionApproved', handlers.approved);
374
+ handlers.approved = undefined;
375
+ }
376
+ if (handlers.rejected) {
377
+ this.messenger.unsubscribe('TransactionController:transactionRejected', handlers.rejected);
378
+ handlers.rejected = undefined;
379
+ }
380
+ };
381
+ // Cleanup function to unsubscribe from all events and clear timeout
382
+ const cleanup = (txIdToRemove, removeFromState = true) => {
383
+ cleanupApprovalHandlers();
384
+ if (handlers.confirmed) {
385
+ this.messenger.unsubscribe('TransactionController:transactionConfirmed', handlers.confirmed);
386
+ }
387
+ if (handlers.failed) {
388
+ this.messenger.unsubscribe('TransactionController:transactionFailed', handlers.failed);
389
+ }
390
+ if (handlers.dropped) {
391
+ this.messenger.unsubscribe('TransactionController:transactionDropped', handlers.dropped);
392
+ }
393
+ if (handlers.timeoutId !== undefined) {
394
+ clearTimeout(handlers.timeoutId);
395
+ }
396
+ // Remove the pending revocation from the state (only if it was added)
397
+ if (removeFromState) {
398
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_removePendingRevocationFromStateByTxId).call(this, txIdToRemove);
399
+ }
400
+ };
401
+ // Handle approved transaction - add to pending revocations state
402
+ handlers.approved = (payload) => {
403
+ if (payload.transactionMeta.id === txId) {
404
+ (0, logger_js_1.controllerLog)('Transaction approved by user, adding to pending revocations', {
405
+ txId,
406
+ permissionContext,
407
+ });
408
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_addPendingRevocationToState).call(this, txId, permissionContext);
409
+ // Unsubscribe from approval/rejection events since decision is made
410
+ cleanupApprovalHandlers();
411
+ }
412
+ };
413
+ // Handle rejected transaction - cleanup without adding to state
414
+ handlers.rejected = (payload) => {
415
+ if (payload.transactionMeta.id === txId) {
416
+ (0, logger_js_1.controllerLog)('Transaction rejected by user, cleaning up listeners', {
417
+ txId,
418
+ permissionContext,
419
+ });
420
+ // Don't remove from state since it was never added
421
+ cleanup(payload.transactionMeta.id, false);
422
+ }
423
+ };
424
+ // Handle confirmed transaction - submit revocation
425
+ handlers.confirmed = (transactionMeta) => {
426
+ if (transactionMeta.id === txId) {
427
+ (0, logger_js_1.controllerLog)('Transaction confirmed, submitting revocation', {
428
+ txId,
429
+ permissionContext,
430
+ txHash: transactionMeta.hash,
431
+ });
432
+ if (transactionMeta.status !== transaction_controller_1.TransactionStatus.confirmed) {
433
+ (0, logger_js_1.controllerLog)('Transaction not confirmed, skipping revocation', {
434
+ txId,
435
+ permissionContext,
436
+ status: transactionMeta.status,
437
+ });
438
+ cleanup(transactionMeta.id);
439
+ refreshPermissions('transaction not confirmed');
440
+ return;
441
+ }
442
+ const txHash = transactionMeta.hash;
443
+ if (txHash === undefined) {
444
+ (0, logger_js_1.controllerLog)('Failed to resolve transaction hash after revocation transaction confirmed', {
445
+ txId,
446
+ permissionContext,
447
+ error: new Error('Confirmed transaction is missing transaction hash'),
448
+ });
449
+ }
450
+ this.submitRevocation({ permissionContext, txHash })
451
+ .catch((error) => {
452
+ (0, logger_js_1.controllerLog)('Failed to submit revocation after transaction confirmed', {
453
+ txId,
454
+ permissionContext,
455
+ error,
456
+ });
457
+ })
458
+ .finally(() => refreshPermissions('transaction confirmed'));
459
+ cleanup(transactionMeta.id);
460
+ }
461
+ };
462
+ // Handle failed transaction - cleanup without submitting revocation
463
+ handlers.failed = (payload) => {
464
+ if (payload.transactionMeta.id === txId) {
465
+ (0, logger_js_1.controllerLog)('Transaction failed, cleaning up revocation listener', {
466
+ txId,
467
+ permissionContext,
468
+ error: payload.error,
469
+ });
470
+ cleanup(payload.transactionMeta.id);
471
+ refreshPermissions('transaction failed');
472
+ }
473
+ };
474
+ // Handle dropped transaction - cleanup without submitting revocation
475
+ handlers.dropped = (payload) => {
476
+ if (payload.transactionMeta.id === txId) {
477
+ (0, logger_js_1.controllerLog)('Transaction dropped, cleaning up revocation listener', {
478
+ txId,
479
+ permissionContext,
480
+ });
481
+ cleanup(payload.transactionMeta.id);
482
+ refreshPermissions('transaction dropped');
483
+ }
484
+ };
485
+ // Subscribe to user approval/rejection events
486
+ this.messenger.subscribe('TransactionController:transactionApproved', handlers.approved);
487
+ this.messenger.subscribe('TransactionController:transactionRejected', handlers.rejected);
488
+ // Subscribe to terminal transaction events
489
+ this.messenger.subscribe('TransactionController:transactionConfirmed', handlers.confirmed);
490
+ this.messenger.subscribe('TransactionController:transactionFailed', handlers.failed);
491
+ this.messenger.subscribe('TransactionController:transactionDropped', handlers.dropped);
492
+ // Set timeout as safety net to prevent memory leaks
493
+ handlers.timeoutId = setTimeout(() => {
494
+ (0, logger_js_1.controllerLog)('Pending revocation timed out, cleaning up listeners', {
495
+ txId,
496
+ permissionContext,
497
+ });
498
+ cleanup(txId);
499
+ }, PENDING_REVOCATION_TIMEOUT);
500
+ }
501
+ /**
502
+ * Submits a revocation directly without requiring an on-chain transaction.
503
+ * Used for already-disabled delegations that don't require an on-chain transaction.
504
+ *
505
+ * This method:
506
+ * 1. Adds the permission context to pending revocations state (disables UI button)
507
+ * 2. Immediately calls submitRevocation to remove from snap storage
508
+ * 3. On success, removes from pending revocations state (re-enables UI button)
509
+ * 4. On failure, keeps in pending revocations so UI can show error/retry state
510
+ *
511
+ * @param params - The revocation parameters containing the permission context.
512
+ * @returns A promise that resolves when the revocation is submitted successfully.
513
+ * @throws {GatorPermissionsProviderError} If the snap request fails.
514
+ */
515
+ async submitDirectRevocation(params) {
516
+ // Use a placeholder txId that doesn't conflict with real transaction IDs
517
+ const placeholderTxId = `no-tx-${params.permissionContext}`;
518
+ // Add to pending revocations state first (disables UI button immediately)
519
+ __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_addPendingRevocationToState).call(this, placeholderTxId, params.permissionContext);
520
+ // Immediately submit the revocation (will remove from pending on success)
521
+ await this.submitRevocation(params);
522
+ }
523
+ /**
524
+ * Checks if a permission context is in the pending revocations list.
525
+ *
526
+ * @param permissionContext - The permission context to check.
527
+ * @returns `true` if the permission context is pending revocation, `false` otherwise.
528
+ */
529
+ isPendingRevocation(permissionContext) {
530
+ const requestedPermissionContextLowercase = permissionContext.toLowerCase();
531
+ return this.state.pendingRevocations.some((pendingRevocation) => pendingRevocation.permissionContext.toLowerCase() ===
532
+ requestedPermissionContextLowercase);
533
+ }
534
+ }
535
+ exports.GatorPermissionsController = GatorPermissionsController;
536
+ _GatorPermissionsController_supportedPermissionTypes = new WeakMap(), _GatorPermissionsController_gatorPermissionsProviderSnapId = new WeakMap(), _GatorPermissionsController_maxSyncIntervalMs = new WeakMap(), _GatorPermissionsController_fetchAndUpdateGatorPermissionsPromise = new WeakMap(), _GatorPermissionsController_instances = new WeakSet(), _GatorPermissionsController_setIsFetchingGatorPermissions = function _GatorPermissionsController_setIsFetchingGatorPermissions(isFetchingGatorPermissions) {
537
+ this.update((state) => {
538
+ state.isFetchingGatorPermissions = isFetchingGatorPermissions;
539
+ });
540
+ }, _GatorPermissionsController_addPendingRevocationToState = function _GatorPermissionsController_addPendingRevocationToState(txId, permissionContext) {
541
+ this.update((state) => {
542
+ state.pendingRevocations = [
543
+ ...state.pendingRevocations,
544
+ { txId, permissionContext },
545
+ ];
546
+ });
547
+ }, _GatorPermissionsController_removePendingRevocationFromStateByTxId = function _GatorPermissionsController_removePendingRevocationFromStateByTxId(txId) {
548
+ this.update((state) => {
549
+ state.pendingRevocations = state.pendingRevocations.filter((pendingRevocations) => pendingRevocations.txId !== txId);
550
+ });
551
+ }, _GatorPermissionsController_removePendingRevocationFromStateByPermissionContext = function _GatorPermissionsController_removePendingRevocationFromStateByPermissionContext(permissionContext) {
552
+ this.update((state) => {
553
+ state.pendingRevocations = state.pendingRevocations.filter((pendingRevocations) => pendingRevocations.permissionContext.toLowerCase() !==
554
+ permissionContext.toLowerCase());
555
+ });
556
+ }, _GatorPermissionsController_buildPreviousStatusByContext = function _GatorPermissionsController_buildPreviousStatusByContext() {
557
+ const map = new Map();
558
+ for (const prev of this.state.grantedPermissions) {
559
+ map.set(prev.permissionResponse.context.toLowerCase(), prev.status ?? 'Active');
560
+ }
561
+ return map;
562
+ }, _GatorPermissionsController_getProviderForChainId = async function _GatorPermissionsController_getProviderForChainId(chainId) {
563
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
564
+ const { provider } = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
565
+ return provider;
566
+ }, _GatorPermissionsController_updateGrantedPermissionsStatus = async function _GatorPermissionsController_updateGrantedPermissionsStatus(grantedPermissions) {
567
+ return (0, permissionOnChainStatus_js_1.updateGrantedPermissionsStatus)(grantedPermissions, {
568
+ getProviderForChainId: (chainId) => __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_getProviderForChainId).call(this, chainId),
569
+ });
570
+ }, _GatorPermissionsController_storedPermissionToPermissionInfo = function _GatorPermissionsController_storedPermissionToPermissionInfo(storedGatorPermission, status) {
571
+ const { permissionResponse: fullPermissionResponse } = storedGatorPermission;
572
+ const { dependencies: _dependencies, to: _to, ...permissionResponse } = fullPermissionResponse;
573
+ return {
574
+ ...storedGatorPermission,
575
+ permissionResponse,
576
+ status,
577
+ };
578
+ }, _GatorPermissionsController_storedPermissionsToPermissionInfoWithMetadata = function _GatorPermissionsController_storedPermissionsToPermissionInfoWithMetadata(storedGatorPermissions) {
579
+ if (!storedGatorPermissions) {
580
+ return [];
581
+ }
582
+ const previousStatusByContext = __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_buildPreviousStatusByContext).call(this);
583
+ return storedGatorPermissions.map((storedPermission) => {
584
+ const previousStatus = previousStatusByContext.get(storedPermission.permissionResponse.context.toLowerCase());
585
+ return __classPrivateFieldGet(this, _GatorPermissionsController_instances, "m", _GatorPermissionsController_storedPermissionToPermissionInfo).call(this, storedPermission, previousStatus ?? 'Active');
586
+ });
587
+ };
588
+ exports.default = GatorPermissionsController;
589
+ //# sourceMappingURL=GatorPermissionsController.cjs.map