@metamask/snaps-controllers 12.3.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -1
- package/dist/cronjob/CronjobController.cjs +250 -276
- package/dist/cronjob/CronjobController.cjs.map +1 -1
- package/dist/cronjob/CronjobController.d.cts +61 -78
- package/dist/cronjob/CronjobController.d.cts.map +1 -1
- package/dist/cronjob/CronjobController.d.mts +61 -78
- package/dist/cronjob/CronjobController.d.mts.map +1 -1
- package/dist/cronjob/CronjobController.mjs +251 -277
- package/dist/cronjob/CronjobController.mjs.map +1 -1
- package/dist/cronjob/utils.cjs +79 -0
- package/dist/cronjob/utils.cjs.map +1 -0
- package/dist/cronjob/utils.d.cts +25 -0
- package/dist/cronjob/utils.d.cts.map +1 -0
- package/dist/cronjob/utils.d.mts +25 -0
- package/dist/cronjob/utils.d.mts.map +1 -0
- package/dist/cronjob/utils.mjs +75 -0
- package/dist/cronjob/utils.mjs.map +1 -0
- package/dist/insights/SnapInsightsController.cjs +199 -149
- package/dist/insights/SnapInsightsController.cjs.map +1 -1
- package/dist/insights/SnapInsightsController.mjs +198 -148
- package/dist/insights/SnapInsightsController.mjs.map +1 -1
- package/dist/interface/SnapInterfaceController.cjs +160 -101
- package/dist/interface/SnapInterfaceController.cjs.map +1 -1
- package/dist/interface/SnapInterfaceController.mjs +160 -101
- package/dist/interface/SnapInterfaceController.mjs.map +1 -1
- package/dist/multichain/MultichainRouter.cjs +117 -114
- package/dist/multichain/MultichainRouter.cjs.map +1 -1
- package/dist/multichain/MultichainRouter.mjs +117 -114
- package/dist/multichain/MultichainRouter.mjs.map +1 -1
- package/dist/services/AbstractExecutionService.cjs +131 -139
- package/dist/services/AbstractExecutionService.cjs.map +1 -1
- package/dist/services/AbstractExecutionService.mjs +131 -139
- package/dist/services/AbstractExecutionService.mjs.map +1 -1
- package/dist/services/ProxyPostMessageStream.cjs +19 -26
- package/dist/services/ProxyPostMessageStream.cjs.map +1 -1
- package/dist/services/ProxyPostMessageStream.mjs +19 -26
- package/dist/services/ProxyPostMessageStream.mjs.map +1 -1
- package/dist/services/iframe/IframeExecutionService.cjs +1 -0
- package/dist/services/iframe/IframeExecutionService.cjs.map +1 -1
- package/dist/services/iframe/IframeExecutionService.mjs +1 -0
- package/dist/services/iframe/IframeExecutionService.mjs.map +1 -1
- package/dist/services/offscreen/OffscreenExecutionService.cjs +3 -16
- package/dist/services/offscreen/OffscreenExecutionService.cjs.map +1 -1
- package/dist/services/offscreen/OffscreenExecutionService.mjs +3 -16
- package/dist/services/offscreen/OffscreenExecutionService.mjs.map +1 -1
- package/dist/services/proxy/ProxyExecutionService.cjs +4 -17
- package/dist/services/proxy/ProxyExecutionService.cjs.map +1 -1
- package/dist/services/proxy/ProxyExecutionService.mjs +4 -17
- package/dist/services/proxy/ProxyExecutionService.mjs.map +1 -1
- package/dist/services/webview/WebViewExecutionService.cjs +6 -19
- package/dist/services/webview/WebViewExecutionService.cjs.map +1 -1
- package/dist/services/webview/WebViewExecutionService.mjs +6 -19
- package/dist/services/webview/WebViewExecutionService.mjs.map +1 -1
- package/dist/services/webview/WebViewMessageStream.cjs +13 -26
- package/dist/services/webview/WebViewMessageStream.cjs.map +1 -1
- package/dist/services/webview/WebViewMessageStream.mjs +13 -26
- package/dist/services/webview/WebViewMessageStream.mjs.map +1 -1
- package/dist/snaps/SnapController.cjs +1370 -1161
- package/dist/snaps/SnapController.cjs.map +1 -1
- package/dist/snaps/SnapController.d.cts +4 -4
- package/dist/snaps/SnapController.d.cts.map +1 -1
- package/dist/snaps/SnapController.d.mts +4 -4
- package/dist/snaps/SnapController.d.mts.map +1 -1
- package/dist/snaps/SnapController.mjs +1370 -1161
- package/dist/snaps/SnapController.mjs.map +1 -1
- package/dist/snaps/Timer.cjs +4 -0
- package/dist/snaps/Timer.cjs.map +1 -1
- package/dist/snaps/Timer.mjs +4 -0
- package/dist/snaps/Timer.mjs.map +1 -1
- package/dist/snaps/location/http.cjs +20 -4
- package/dist/snaps/location/http.cjs.map +1 -1
- package/dist/snaps/location/http.mjs +20 -4
- package/dist/snaps/location/http.mjs.map +1 -1
- package/dist/snaps/location/local.cjs +4 -17
- package/dist/snaps/location/local.cjs.map +1 -1
- package/dist/snaps/location/local.mjs +4 -17
- package/dist/snaps/location/local.mjs.map +1 -1
- package/dist/snaps/location/npm.cjs +28 -48
- package/dist/snaps/location/npm.cjs.map +1 -1
- package/dist/snaps/location/npm.d.cts.map +1 -1
- package/dist/snaps/location/npm.d.mts.map +1 -1
- package/dist/snaps/location/npm.mjs +28 -48
- package/dist/snaps/location/npm.mjs.map +1 -1
- package/dist/snaps/registry/json.cjs +173 -166
- package/dist/snaps/registry/json.cjs.map +1 -1
- package/dist/snaps/registry/json.mjs +172 -165
- package/dist/snaps/registry/json.mjs.map +1 -1
- package/package.json +9 -9
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
-
};
|
|
8
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
-
};
|
|
13
|
-
var _CronjobController_instances, _CronjobController_dailyTimer, _CronjobController_timers, _CronjobController_snapIds, _CronjobController_getAllJobs, _CronjobController_getSnapJobs, _CronjobController_schedule, _CronjobController_executeCronjob, _CronjobController_setUpBackgroundEvent, _CronjobController_updateJobLastRunState, _CronjobController_rescheduleBackgroundEvents;
|
|
14
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
3
|
exports.CronjobController = exports.DAILY_TIMEOUT = void 0;
|
|
16
4
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -20,106 +8,67 @@ const utils_1 = require("@metamask/utils");
|
|
|
20
8
|
const immer_1 = require("immer");
|
|
21
9
|
const luxon_1 = require("luxon");
|
|
22
10
|
const nanoid_1 = require("nanoid");
|
|
23
|
-
const
|
|
11
|
+
const utils_2 = require("./utils.cjs");
|
|
12
|
+
const constants_1 = require("../snaps/constants.cjs");
|
|
24
13
|
const Timer_1 = require("../snaps/Timer.cjs");
|
|
25
14
|
exports.DAILY_TIMEOUT = (0, utils_1.inMilliseconds)(24, utils_1.Duration.Hour);
|
|
26
15
|
const controllerName = 'CronjobController';
|
|
27
16
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
17
|
+
* The cronjob controller is responsible for managing cronjobs and background
|
|
18
|
+
* events for Snaps. It allows Snaps to schedule events that will be executed
|
|
19
|
+
* at a later time.
|
|
30
20
|
*/
|
|
31
21
|
class CronjobController extends base_controller_1.BaseController {
|
|
22
|
+
#timers;
|
|
23
|
+
#dailyTimer = new Timer_1.Timer(exports.DAILY_TIMEOUT);
|
|
32
24
|
constructor({ messenger, state }) {
|
|
33
25
|
super({
|
|
34
26
|
messenger,
|
|
35
27
|
metadata: {
|
|
36
|
-
jobs: { persist: true, anonymous: false },
|
|
37
28
|
events: { persist: true, anonymous: false },
|
|
38
29
|
},
|
|
39
30
|
name: controllerName,
|
|
40
31
|
state: {
|
|
41
|
-
jobs: {},
|
|
42
32
|
events: {},
|
|
43
33
|
...state,
|
|
44
34
|
},
|
|
45
35
|
});
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
this.
|
|
55
|
-
|
|
56
|
-
this
|
|
57
|
-
this
|
|
58
|
-
this._handleSnapEnabledEvent = this._handleSnapEnabledEvent.bind(this);
|
|
59
|
-
// Subscribe to Snap events
|
|
60
|
-
/* eslint-disable @typescript-eslint/unbound-method */
|
|
61
|
-
this.messagingSystem.subscribe('SnapController:snapInstalled', this._handleSnapRegisterEvent);
|
|
62
|
-
this.messagingSystem.subscribe('SnapController:snapUninstalled', this._handleSnapUnregisterEvent);
|
|
63
|
-
this.messagingSystem.subscribe('SnapController:snapEnabled', this._handleSnapEnabledEvent);
|
|
64
|
-
this.messagingSystem.subscribe('SnapController:snapDisabled', this._handleSnapDisabledEvent);
|
|
65
|
-
this.messagingSystem.subscribe('SnapController:snapUpdated', this._handleEventSnapUpdated);
|
|
66
|
-
/* eslint-enable @typescript-eslint/unbound-method */
|
|
67
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:scheduleBackgroundEvent`, (...args) => this.scheduleBackgroundEvent(...args));
|
|
68
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:cancelBackgroundEvent`, (...args) => this.cancelBackgroundEvent(...args));
|
|
69
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:getBackgroundEvents`, (...args) => this.getBackgroundEvents(...args));
|
|
70
|
-
this.dailyCheckIn();
|
|
71
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_rescheduleBackgroundEvents).call(this, Object.values(this.state.events));
|
|
36
|
+
this.#timers = new Map();
|
|
37
|
+
this.messagingSystem.subscribe('SnapController:snapInstalled', this.#handleSnapInstalledEvent);
|
|
38
|
+
this.messagingSystem.subscribe('SnapController:snapUninstalled', this.#handleSnapUninstalledEvent);
|
|
39
|
+
this.messagingSystem.subscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
40
|
+
this.messagingSystem.subscribe('SnapController:snapDisabled', this.#handleSnapDisabledEvent);
|
|
41
|
+
this.messagingSystem.subscribe('SnapController:snapUpdated', this.#handleSnapUpdatedEvent);
|
|
42
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:schedule`, (...args) => this.schedule(...args));
|
|
43
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:cancel`, (...args) => this.cancel(...args));
|
|
44
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:get`, (...args) => this.get(...args));
|
|
45
|
+
this.#start();
|
|
46
|
+
this.#clear();
|
|
47
|
+
this.#reschedule();
|
|
72
48
|
}
|
|
73
49
|
/**
|
|
74
|
-
*
|
|
75
|
-
* Once registered, each job will be scheduled.
|
|
50
|
+
* Schedule a non-recurring background event.
|
|
76
51
|
*
|
|
77
|
-
* @param
|
|
78
|
-
|
|
79
|
-
register(snapId) {
|
|
80
|
-
const jobs = __classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_getSnapJobs).call(this, snapId);
|
|
81
|
-
jobs?.forEach((job) => __classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_schedule).call(this, job));
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Schedule a background event.
|
|
85
|
-
*
|
|
86
|
-
* @param backgroundEventWithoutId - Background event.
|
|
87
|
-
* @returns An id representing the background event.
|
|
52
|
+
* @param event - The event to schedule.
|
|
53
|
+
* @returns The ID of the scheduled event.
|
|
88
54
|
*/
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.startOf('second')
|
|
94
|
-
.toISO({
|
|
95
|
-
suppressMilliseconds: true,
|
|
55
|
+
schedule(event) {
|
|
56
|
+
return this.#add({
|
|
57
|
+
...event,
|
|
58
|
+
recurring: false,
|
|
96
59
|
});
|
|
97
|
-
(0, utils_1.assert)(scheduledAt);
|
|
98
|
-
const event = {
|
|
99
|
-
...backgroundEventWithoutId,
|
|
100
|
-
id: (0, nanoid_1.nanoid)(),
|
|
101
|
-
scheduledAt,
|
|
102
|
-
};
|
|
103
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_setUpBackgroundEvent).call(this, event);
|
|
104
|
-
return event.id;
|
|
105
60
|
}
|
|
106
61
|
/**
|
|
107
|
-
* Cancel
|
|
62
|
+
* Cancel an event.
|
|
108
63
|
*
|
|
109
64
|
* @param origin - The origin making the cancel call.
|
|
110
|
-
* @param id - The id of the
|
|
65
|
+
* @param id - The id of the event to cancel.
|
|
111
66
|
* @throws If the event does not exist.
|
|
112
67
|
*/
|
|
113
|
-
|
|
68
|
+
cancel(origin, id) {
|
|
114
69
|
(0, utils_1.assert)(this.state.events[id], `A background event with the id of "${id}" does not exist.`);
|
|
115
70
|
(0, utils_1.assert)(this.state.events[id].snapId === origin, 'Only the origin that scheduled this event can cancel it.');
|
|
116
|
-
|
|
117
|
-
timer?.cancel();
|
|
118
|
-
__classPrivateFieldGet(this, _CronjobController_timers, "f").delete(id);
|
|
119
|
-
__classPrivateFieldGet(this, _CronjobController_snapIds, "f").delete(id);
|
|
120
|
-
this.update((state) => {
|
|
121
|
-
delete state.events[id];
|
|
122
|
-
});
|
|
71
|
+
this.#cancel(id);
|
|
123
72
|
}
|
|
124
73
|
/**
|
|
125
74
|
* Get a list of a Snap's background events.
|
|
@@ -127,252 +76,277 @@ class CronjobController extends base_controller_1.BaseController {
|
|
|
127
76
|
* @param snapId - The id of the Snap to fetch background events for.
|
|
128
77
|
* @returns An array of background events.
|
|
129
78
|
*/
|
|
130
|
-
|
|
79
|
+
get(snapId) {
|
|
131
80
|
return Object.values(this.state.events)
|
|
132
|
-
.filter((snapEvent) => snapEvent.snapId === snapId)
|
|
81
|
+
.filter((snapEvent) => snapEvent.snapId === snapId && !snapEvent.recurring)
|
|
133
82
|
.map((event) => ({
|
|
134
83
|
...event,
|
|
135
|
-
// Truncate dates to remove milliseconds.
|
|
136
84
|
date: (0, snaps_utils_1.toCensoredISO8601String)(event.date),
|
|
85
|
+
scheduledAt: (0, snaps_utils_1.toCensoredISO8601String)(event.scheduledAt),
|
|
137
86
|
}));
|
|
138
87
|
}
|
|
139
88
|
/**
|
|
140
|
-
*
|
|
89
|
+
* Register cronjobs for a given Snap by getting specification from the
|
|
90
|
+
* permission caveats. Once registered, each job will be scheduled.
|
|
141
91
|
*
|
|
142
|
-
* @param snapId - ID
|
|
143
|
-
* @param skipEvents - Whether the unregistration process should skip scheduled background events.
|
|
92
|
+
* @param snapId - The snap ID to register jobs for.
|
|
144
93
|
*/
|
|
145
|
-
|
|
146
|
-
const jobs =
|
|
147
|
-
|
|
148
|
-
const eventIds = [];
|
|
149
|
-
jobs.forEach(([id]) => {
|
|
150
|
-
const timer = __classPrivateFieldGet(this, _CronjobController_timers, "f").get(id);
|
|
151
|
-
if (timer) {
|
|
152
|
-
timer.cancel();
|
|
153
|
-
__classPrivateFieldGet(this, _CronjobController_timers, "f").delete(id);
|
|
154
|
-
__classPrivateFieldGet(this, _CronjobController_snapIds, "f").delete(id);
|
|
155
|
-
if (!skipEvents && this.state.events[id]) {
|
|
156
|
-
eventIds.push(id);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
if (eventIds.length > 0) {
|
|
161
|
-
this.update((state) => {
|
|
162
|
-
eventIds.forEach((id) => {
|
|
163
|
-
delete state.events[id];
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
94
|
+
register(snapId) {
|
|
95
|
+
const jobs = this.#getSnapCronjobs(snapId);
|
|
96
|
+
jobs?.forEach((job) => this.#add(job));
|
|
168
97
|
}
|
|
169
98
|
/**
|
|
170
|
-
*
|
|
99
|
+
* Unregister all cronjobs and background events for a given Snap.
|
|
171
100
|
*
|
|
172
|
-
*
|
|
101
|
+
* @param snapId - ID of a snap.
|
|
173
102
|
*/
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const lastRun = this.state.jobs[job.id]?.lastRun;
|
|
179
|
-
// If a job was supposed to run while we were shut down but wasn't we run it now
|
|
180
|
-
if (lastRun !== undefined &&
|
|
181
|
-
parsed.hasPrev() &&
|
|
182
|
-
parsed.prev().getTime() > lastRun) {
|
|
183
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_executeCronjob).call(this, job).catch((error) => {
|
|
184
|
-
(0, snaps_utils_1.logError)(error);
|
|
185
|
-
});
|
|
103
|
+
unregister(snapId) {
|
|
104
|
+
for (const [id, event] of Object.entries(this.state.events)) {
|
|
105
|
+
if (event.snapId === snapId) {
|
|
106
|
+
this.#cancel(id);
|
|
186
107
|
}
|
|
187
|
-
// Try scheduling, will fail if an existing scheduled job is found
|
|
188
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_schedule).call(this, job);
|
|
189
108
|
}
|
|
190
|
-
__classPrivateFieldSet(this, _CronjobController_dailyTimer, new Timer_1.Timer(exports.DAILY_TIMEOUT), "f");
|
|
191
|
-
__classPrivateFieldGet(this, _CronjobController_dailyTimer, "f").start(() => {
|
|
192
|
-
this.dailyCheckIn();
|
|
193
|
-
});
|
|
194
109
|
}
|
|
195
110
|
/**
|
|
196
111
|
* Run controller teardown process and unsubscribe from Snap events.
|
|
197
112
|
*/
|
|
198
113
|
destroy() {
|
|
199
114
|
super.destroy();
|
|
200
|
-
|
|
201
|
-
this.messagingSystem.unsubscribe('SnapController:
|
|
202
|
-
this.messagingSystem.unsubscribe('SnapController:
|
|
203
|
-
this.messagingSystem.unsubscribe('SnapController:
|
|
204
|
-
this.messagingSystem.unsubscribe('SnapController:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
115
|
+
this.messagingSystem.unsubscribe('SnapController:snapInstalled', this.#handleSnapInstalledEvent);
|
|
116
|
+
this.messagingSystem.unsubscribe('SnapController:snapUninstalled', this.#handleSnapUninstalledEvent);
|
|
117
|
+
this.messagingSystem.unsubscribe('SnapController:snapEnabled', this.#handleSnapEnabledEvent);
|
|
118
|
+
this.messagingSystem.unsubscribe('SnapController:snapDisabled', this.#handleSnapDisabledEvent);
|
|
119
|
+
this.messagingSystem.unsubscribe('SnapController:snapUpdated', this.#handleSnapUpdatedEvent);
|
|
120
|
+
// Cancel all timers and clear the map.
|
|
121
|
+
this.#timers.forEach((timer) => timer.cancel());
|
|
122
|
+
this.#timers.clear();
|
|
123
|
+
if (this.#dailyTimer.status === 'running') {
|
|
124
|
+
this.#dailyTimer.cancel();
|
|
125
|
+
}
|
|
208
126
|
}
|
|
209
127
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* @param snap - Basic Snap information.
|
|
128
|
+
* Start the daily timer that will reschedule events every 24 hours.
|
|
213
129
|
*/
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
130
|
+
#start() {
|
|
131
|
+
this.#dailyTimer = new Timer_1.Timer(exports.DAILY_TIMEOUT);
|
|
132
|
+
this.#dailyTimer.start(() => {
|
|
133
|
+
this.#reschedule();
|
|
134
|
+
this.#start();
|
|
135
|
+
});
|
|
219
136
|
}
|
|
220
137
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
138
|
+
* Add a cronjob or background event to the controller state and schedule it
|
|
139
|
+
* for execution.
|
|
223
140
|
*
|
|
224
|
-
* @param
|
|
141
|
+
* @param event - The event to schedule.
|
|
142
|
+
* @returns The ID of the scheduled event.
|
|
225
143
|
*/
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
144
|
+
#add(event) {
|
|
145
|
+
const id = event.id ?? (0, nanoid_1.nanoid)();
|
|
146
|
+
const internalEvent = {
|
|
147
|
+
...event,
|
|
148
|
+
id,
|
|
149
|
+
date: (0, utils_2.getExecutionDate)(event.schedule),
|
|
150
|
+
scheduledAt: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
this.update((state) => {
|
|
153
|
+
state.events[internalEvent.id] = (0, immer_1.castDraft)(internalEvent);
|
|
154
|
+
});
|
|
155
|
+
this.#schedule(internalEvent);
|
|
156
|
+
return id;
|
|
233
157
|
}
|
|
234
158
|
/**
|
|
235
|
-
*
|
|
159
|
+
* Get the next execution date for a given event and start a timer for it.
|
|
236
160
|
*
|
|
237
|
-
* @param
|
|
161
|
+
* @param event - The event to schedule.
|
|
238
162
|
*/
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
163
|
+
#schedule(event) {
|
|
164
|
+
const date = (0, utils_2.getExecutionDate)(event.schedule);
|
|
165
|
+
this.update((state) => {
|
|
166
|
+
state.events[event.id].date = date;
|
|
167
|
+
});
|
|
168
|
+
this.#startTimer({
|
|
169
|
+
...event,
|
|
170
|
+
date,
|
|
171
|
+
});
|
|
244
172
|
}
|
|
245
173
|
/**
|
|
246
|
-
*
|
|
174
|
+
* Set up and start a timer for the given event.
|
|
247
175
|
*
|
|
248
|
-
* @param
|
|
176
|
+
* @param event - The event to schedule.
|
|
177
|
+
* @throws If the event is scheduled in the past.
|
|
249
178
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
179
|
+
#startTimer(event) {
|
|
180
|
+
const ms = luxon_1.DateTime.fromISO(event.date, { setZone: true }).toMillis() - Date.now();
|
|
181
|
+
// We don't schedule this job yet as it is too far in the future.
|
|
182
|
+
if (ms > exports.DAILY_TIMEOUT) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const timer = new Timer_1.Timer(ms);
|
|
186
|
+
timer.start(() => {
|
|
187
|
+
this.#execute(event);
|
|
188
|
+
});
|
|
189
|
+
this.#timers.set(event.id, timer);
|
|
255
190
|
}
|
|
256
191
|
/**
|
|
257
|
-
*
|
|
192
|
+
* Execute a background event. This method is called when the event's timer
|
|
193
|
+
* expires.
|
|
258
194
|
*
|
|
259
|
-
*
|
|
195
|
+
* If the event is not recurring, it will be removed from the state after
|
|
196
|
+
* execution. If it is recurring, it will be rescheduled.
|
|
197
|
+
*
|
|
198
|
+
* @param event - The event to execute.
|
|
260
199
|
*/
|
|
261
|
-
|
|
262
|
-
// ignore.
|
|
263
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
264
|
-
_handleEventSnapUpdated(snap) {
|
|
265
|
-
this.unregister(snap.id);
|
|
266
|
-
this.register(snap.id);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
exports.CronjobController = CronjobController;
|
|
270
|
-
_CronjobController_dailyTimer = new WeakMap(), _CronjobController_timers = new WeakMap(), _CronjobController_snapIds = new WeakMap(), _CronjobController_instances = new WeakSet(), _CronjobController_getAllJobs = function _CronjobController_getAllJobs() {
|
|
271
|
-
const snaps = this.messagingSystem.call('SnapController:getAll');
|
|
272
|
-
const filteredSnaps = (0, __1.getRunnableSnaps)(snaps);
|
|
273
|
-
const jobs = filteredSnaps.map((snap) => __classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_getSnapJobs).call(this, snap.id));
|
|
274
|
-
return jobs.flat().filter((job) => job !== undefined);
|
|
275
|
-
}, _CronjobController_getSnapJobs = function _CronjobController_getSnapJobs(snapId) {
|
|
276
|
-
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
277
|
-
const permission = permissions?.[snaps_rpc_methods_1.SnapEndowments.Cronjob];
|
|
278
|
-
const definitions = (0, snaps_rpc_methods_1.getCronjobCaveatJobs)(permission);
|
|
279
|
-
return definitions?.map((definition, idx) => {
|
|
280
|
-
return { ...definition, id: `${snapId}-${idx}`, snapId };
|
|
281
|
-
});
|
|
282
|
-
}, _CronjobController_schedule = function _CronjobController_schedule(job) {
|
|
283
|
-
if (__classPrivateFieldGet(this, _CronjobController_timers, "f").has(job.id)) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
const parsed = (0, snaps_utils_1.parseCronExpression)(job.expression);
|
|
287
|
-
const next = parsed.next();
|
|
288
|
-
const now = new Date();
|
|
289
|
-
const ms = next.getTime() - now.getTime();
|
|
290
|
-
// Don't schedule this job yet as it is too far in the future
|
|
291
|
-
if (ms > exports.DAILY_TIMEOUT) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
const timer = new Timer_1.Timer(ms);
|
|
295
|
-
timer.start(() => {
|
|
296
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_executeCronjob).call(this, job).catch((error) => {
|
|
297
|
-
// TODO: Decide how to handle errors.
|
|
298
|
-
(0, snaps_utils_1.logError)(error);
|
|
299
|
-
});
|
|
300
|
-
__classPrivateFieldGet(this, _CronjobController_timers, "f").delete(job.id);
|
|
301
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_schedule).call(this, job);
|
|
302
|
-
});
|
|
303
|
-
if (!this.state.jobs[job.id]?.lastRun) {
|
|
304
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_updateJobLastRunState).call(this, job.id, 0); // 0 for init, never ran actually
|
|
305
|
-
}
|
|
306
|
-
__classPrivateFieldGet(this, _CronjobController_timers, "f").set(job.id, timer);
|
|
307
|
-
__classPrivateFieldGet(this, _CronjobController_snapIds, "f").set(job.id, job.snapId);
|
|
308
|
-
}, _CronjobController_executeCronjob =
|
|
309
|
-
/**
|
|
310
|
-
* Execute job.
|
|
311
|
-
*
|
|
312
|
-
* @param job - Cronjob specification.
|
|
313
|
-
*/
|
|
314
|
-
async function _CronjobController_executeCronjob(job) {
|
|
315
|
-
__classPrivateFieldGet(this, _CronjobController_instances, "m", _CronjobController_updateJobLastRunState).call(this, job.id, Date.now());
|
|
316
|
-
await this.messagingSystem.call('SnapController:handleRequest', {
|
|
317
|
-
snapId: job.snapId,
|
|
318
|
-
origin: 'metamask',
|
|
319
|
-
handler: snaps_utils_1.HandlerType.OnCronjob,
|
|
320
|
-
request: job.request,
|
|
321
|
-
});
|
|
322
|
-
}, _CronjobController_setUpBackgroundEvent = function _CronjobController_setUpBackgroundEvent(event) {
|
|
323
|
-
const date = new Date(event.date);
|
|
324
|
-
const now = new Date();
|
|
325
|
-
const ms = date.getTime() - now.getTime();
|
|
326
|
-
if (ms <= 0) {
|
|
327
|
-
throw new Error('Cannot schedule an event in the past.');
|
|
328
|
-
}
|
|
329
|
-
// The event may already be in state when we get here.
|
|
330
|
-
if (!(0, utils_1.hasProperty)(this.state.events, event.id)) {
|
|
331
|
-
this.update((state) => {
|
|
332
|
-
state.events[event.id] = (0, immer_1.castDraft)(event);
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
const timer = new Timer_1.Timer(ms);
|
|
336
|
-
timer.start(() => {
|
|
200
|
+
#execute(event) {
|
|
337
201
|
this.messagingSystem
|
|
338
202
|
.call('SnapController:handleRequest', {
|
|
339
203
|
snapId: event.snapId,
|
|
340
|
-
origin:
|
|
204
|
+
origin: constants_1.METAMASK_ORIGIN,
|
|
341
205
|
handler: snaps_utils_1.HandlerType.OnCronjob,
|
|
342
206
|
request: event.request,
|
|
343
207
|
})
|
|
344
208
|
.catch((error) => {
|
|
345
|
-
(0, snaps_utils_1.logError)(error);
|
|
209
|
+
(0, snaps_utils_1.logError)(`An error occurred while executing an event for Snap "${event.snapId}":`, error);
|
|
346
210
|
});
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
__classPrivateFieldGet(this, _CronjobController_timers, "f").set(event.id, timer);
|
|
354
|
-
__classPrivateFieldGet(this, _CronjobController_snapIds, "f").set(event.id, event.snapId);
|
|
355
|
-
}, _CronjobController_updateJobLastRunState = function _CronjobController_updateJobLastRunState(jobId, lastRun) {
|
|
356
|
-
this.update((state) => {
|
|
357
|
-
state.jobs[jobId] = {
|
|
358
|
-
lastRun,
|
|
359
|
-
};
|
|
360
|
-
});
|
|
361
|
-
}, _CronjobController_rescheduleBackgroundEvents = function _CronjobController_rescheduleBackgroundEvents(backgroundEvents) {
|
|
362
|
-
for (const snapEvent of backgroundEvents) {
|
|
363
|
-
const { date } = snapEvent;
|
|
364
|
-
const now = new Date();
|
|
365
|
-
const then = new Date(date);
|
|
366
|
-
if (then.getTime() < now.getTime()) {
|
|
367
|
-
// Remove expired events from state
|
|
211
|
+
this.#timers.delete(event.id);
|
|
212
|
+
// Non-recurring events are removed from the state after execution, and
|
|
213
|
+
// recurring events are rescheduled.
|
|
214
|
+
if (!event.recurring) {
|
|
368
215
|
this.update((state) => {
|
|
369
|
-
delete state.events[
|
|
216
|
+
delete state.events[event.id];
|
|
370
217
|
});
|
|
371
|
-
|
|
218
|
+
return;
|
|
372
219
|
}
|
|
373
|
-
|
|
374
|
-
|
|
220
|
+
this.#schedule(event);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Cancel a background event by its ID. Unlike {@link cancel}, this method
|
|
224
|
+
* does not check the origin of the event, so it can be used internally.
|
|
225
|
+
*
|
|
226
|
+
* @param id - The ID of the background event to cancel.
|
|
227
|
+
*/
|
|
228
|
+
#cancel(id) {
|
|
229
|
+
const timer = this.#timers.get(id);
|
|
230
|
+
timer?.cancel();
|
|
231
|
+
this.#timers.delete(id);
|
|
232
|
+
this.update((state) => {
|
|
233
|
+
delete state.events[id];
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Retrieve all cronjob specifications for a Snap.
|
|
238
|
+
*
|
|
239
|
+
* @param snapId - ID of a Snap.
|
|
240
|
+
* @returns Array of cronjob specifications.
|
|
241
|
+
*/
|
|
242
|
+
#getSnapCronjobs(snapId) {
|
|
243
|
+
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
244
|
+
const permission = permissions?.[snaps_rpc_methods_1.SnapEndowments.Cronjob];
|
|
245
|
+
const definitions = (0, snaps_rpc_methods_1.getCronjobCaveatJobs)(permission);
|
|
246
|
+
if (!definitions) {
|
|
247
|
+
return [];
|
|
375
248
|
}
|
|
249
|
+
return definitions.map((definition, idx) => {
|
|
250
|
+
return {
|
|
251
|
+
snapId,
|
|
252
|
+
id: `cronjob-${snapId}-${idx}`,
|
|
253
|
+
request: definition.request,
|
|
254
|
+
schedule: (0, utils_2.getCronjobSpecificationSchedule)(definition),
|
|
255
|
+
recurring: true,
|
|
256
|
+
};
|
|
257
|
+
});
|
|
376
258
|
}
|
|
377
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Handle events that should cause cron jobs to be registered.
|
|
261
|
+
*
|
|
262
|
+
* @param snap - Basic Snap information.
|
|
263
|
+
*/
|
|
264
|
+
#handleSnapInstalledEvent = (snap) => {
|
|
265
|
+
this.register(snap.id);
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Handle the Snap enabled event. This checks if the Snap has any cronjobs or
|
|
269
|
+
* background events that need to be rescheduled.
|
|
270
|
+
*
|
|
271
|
+
* @param snap - Basic Snap information.
|
|
272
|
+
*/
|
|
273
|
+
#handleSnapEnabledEvent = (snap) => {
|
|
274
|
+
const events = this.get(snap.id);
|
|
275
|
+
this.#reschedule(events);
|
|
276
|
+
this.register(snap.id);
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Handle events that should cause cronjobs and background events to be
|
|
280
|
+
* unregistered.
|
|
281
|
+
*
|
|
282
|
+
* @param snap - Basic Snap information.
|
|
283
|
+
*/
|
|
284
|
+
#handleSnapUninstalledEvent = (snap) => {
|
|
285
|
+
this.unregister(snap.id);
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Handle events that should cause cronjobs and background events to be
|
|
289
|
+
* unregistered.
|
|
290
|
+
*
|
|
291
|
+
* @param snap - Basic Snap information.
|
|
292
|
+
*/
|
|
293
|
+
#handleSnapDisabledEvent = (snap) => {
|
|
294
|
+
this.unregister(snap.id);
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* Handle cron jobs on 'snapUpdated' event.
|
|
298
|
+
*
|
|
299
|
+
* @param snap - Basic Snap information.
|
|
300
|
+
*/
|
|
301
|
+
#handleSnapUpdatedEvent = (snap) => {
|
|
302
|
+
this.unregister(snap.id);
|
|
303
|
+
this.register(snap.id);
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Reschedule events that are yet to be executed. This should be called on
|
|
307
|
+
* controller initialization and once every 24 hours to ensure that
|
|
308
|
+
* background events are scheduled correctly.
|
|
309
|
+
*
|
|
310
|
+
* @param events - An array of events to reschedule. Defaults to all events in
|
|
311
|
+
* the controller state.
|
|
312
|
+
*/
|
|
313
|
+
#reschedule(events = Object.values(this.state.events)) {
|
|
314
|
+
const now = Date.now();
|
|
315
|
+
for (const event of events) {
|
|
316
|
+
if (this.#timers.has(event.id)) {
|
|
317
|
+
// If the timer for this event already exists, we don't need to
|
|
318
|
+
// reschedule it.
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const eventDate = luxon_1.DateTime.fromISO(event.date, {
|
|
322
|
+
setZone: true,
|
|
323
|
+
})
|
|
324
|
+
.toUTC()
|
|
325
|
+
.toMillis();
|
|
326
|
+
// If the event is recurring and the date is in the past, execute it
|
|
327
|
+
// immediately.
|
|
328
|
+
if (event.recurring && eventDate <= now) {
|
|
329
|
+
this.#execute(event);
|
|
330
|
+
}
|
|
331
|
+
this.#schedule(event);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Clear non-recurring events that are past their scheduled time.
|
|
336
|
+
*/
|
|
337
|
+
#clear() {
|
|
338
|
+
const now = Date.now();
|
|
339
|
+
for (const event of Object.values(this.state.events)) {
|
|
340
|
+
const eventDate = luxon_1.DateTime.fromISO(event.date, {
|
|
341
|
+
setZone: true,
|
|
342
|
+
})
|
|
343
|
+
.toUTC()
|
|
344
|
+
.toMillis();
|
|
345
|
+
if (!event.recurring && eventDate < now) {
|
|
346
|
+
this.#cancel(event.id);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
exports.CronjobController = CronjobController;
|
|
378
352
|
//# sourceMappingURL=CronjobController.cjs.map
|