@metamask/polling-controller 0.0.0 → 0.2.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 CHANGED
@@ -6,4 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- [Unreleased]: https://github.com/MetaMask/core/
9
+ ## [0.2.0]
10
+ ### Added
11
+ - Add way to start and stop different polling sessions for the same network client ID by providing extra scoping data ([#1776](https://github.com/MetaMask/core/pull/1776))
12
+ - Add optional second argument to `stopPollingByPollingToken` (formerly `stopPollingByNetworkClientId`)
13
+ - Add optional second argument to `onPollingCompleteByNetworkClientId`
14
+
15
+ ### Changed
16
+ - **BREAKING:** Bump dependency and peer dependency on `@metamask/network-controller` to ^15.0.0
17
+ - **BREAKING:** Polling controllers are expected to override `_executePoll` instead of `executePoll` ([#1810](https://github.com/MetaMask/core/pull/1810))
18
+ - **BREAKING:** Rename `stopPollingByNetworkClientId` to `stopPollingByPollingToken` ([#1810](https://github.com/MetaMask/core/pull/1810))
19
+ - Add dependency on `fast-json-stable-stringify` ^2.1.0
20
+
21
+ ## [0.1.0]
22
+ ### Added
23
+ - Initial release
24
+
25
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/polling-controller@0.2.0...HEAD
26
+ [0.2.0]: https://github.com/MetaMask/core/compare/@metamask/polling-controller@0.1.0...@metamask/polling-controller@0.2.0
27
+ [0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/polling-controller@0.1.0
@@ -0,0 +1,112 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ /// <reference types="node" />
6
+ import { BaseController, BaseControllerV2 } from '@metamask/base-controller';
7
+ import type { NetworkClientId } from '@metamask/network-controller';
8
+ import type { Json } from '@metamask/utils';
9
+ /**
10
+ * Returns a unique key for a networkClientId and options. This is used to group networkClientId polls with the same options
11
+ * @param networkClientId - The networkClientId to get a key for
12
+ * @param options - The options used to group the polling events
13
+ * @returns The unique key
14
+ */
15
+ export declare const getKey: (networkClientId: NetworkClientId, options: Json) => PollingTokenSetId;
16
+ declare type PollingTokenSetId = `${NetworkClientId}:${string}`;
17
+ export declare const PollingController: (abstract new (...args: any[]) => {
18
+ readonly "__#86357@#pollingTokenSets": Map<PollingTokenSetId, Set<string>>;
19
+ readonly "__#86357@#intervalIds": Record<PollingTokenSetId, NodeJS.Timeout>;
20
+ "__#86357@#callbacks": Map<string, Set<(networkClientId: NetworkClientId) => void>>;
21
+ "__#86357@#intervalLength": number;
22
+ getIntervalLength(): number;
23
+ /**
24
+ * Sets the length of the polling interval
25
+ *
26
+ * @param length - The length of the polling interval in milliseconds
27
+ */
28
+ setIntervalLength(length: number): void;
29
+ /**
30
+ * Starts polling for a networkClientId
31
+ *
32
+ * @param networkClientId - The networkClientId to start polling for
33
+ * @param options - The options used to group the polling events
34
+ * @returns void
35
+ */
36
+ startPollingByNetworkClientId(networkClientId: NetworkClientId, options?: Json): string;
37
+ /**
38
+ * Stops polling for all networkClientIds
39
+ */
40
+ stopAllPolling(): void;
41
+ /**
42
+ * Stops polling for a networkClientId
43
+ *
44
+ * @param pollingToken - The polling token to stop polling for
45
+ */
46
+ stopPollingByPollingToken(pollingToken: string): void;
47
+ /**
48
+ * Executes the poll for a networkClientId
49
+ *
50
+ * @param networkClientId - The networkClientId to execute the poll for
51
+ * @param options - The options passed to startPollingByNetworkClientId
52
+ */
53
+ _executePoll(networkClientId: NetworkClientId, options: Json): Promise<void>;
54
+ "__#86357@#poll"(networkClientId: NetworkClientId, options: Json): void;
55
+ /**
56
+ * Adds a callback to execute when polling is complete
57
+ *
58
+ * @param networkClientId - The networkClientId to listen for polling complete events
59
+ * @param callback - The callback to execute when polling is complete
60
+ * @param options - The options used to group the polling events
61
+ */
62
+ onPollingCompleteByNetworkClientId(networkClientId: NetworkClientId, callback: (networkClientId: NetworkClientId) => void, options?: Json): void;
63
+ }) & typeof BaseControllerV2;
64
+ export declare const PollingControllerV1: (abstract new (...args: any[]) => {
65
+ readonly "__#86357@#pollingTokenSets": Map<PollingTokenSetId, Set<string>>;
66
+ readonly "__#86357@#intervalIds": Record<PollingTokenSetId, NodeJS.Timeout>;
67
+ "__#86357@#callbacks": Map<string, Set<(networkClientId: NetworkClientId) => void>>;
68
+ "__#86357@#intervalLength": number;
69
+ getIntervalLength(): number;
70
+ /**
71
+ * Sets the length of the polling interval
72
+ *
73
+ * @param length - The length of the polling interval in milliseconds
74
+ */
75
+ setIntervalLength(length: number): void;
76
+ /**
77
+ * Starts polling for a networkClientId
78
+ *
79
+ * @param networkClientId - The networkClientId to start polling for
80
+ * @param options - The options used to group the polling events
81
+ * @returns void
82
+ */
83
+ startPollingByNetworkClientId(networkClientId: NetworkClientId, options?: Json): string;
84
+ /**
85
+ * Stops polling for all networkClientIds
86
+ */
87
+ stopAllPolling(): void;
88
+ /**
89
+ * Stops polling for a networkClientId
90
+ *
91
+ * @param pollingToken - The polling token to stop polling for
92
+ */
93
+ stopPollingByPollingToken(pollingToken: string): void;
94
+ /**
95
+ * Executes the poll for a networkClientId
96
+ *
97
+ * @param networkClientId - The networkClientId to execute the poll for
98
+ * @param options - The options passed to startPollingByNetworkClientId
99
+ */
100
+ _executePoll(networkClientId: NetworkClientId, options: Json): Promise<void>;
101
+ "__#86357@#poll"(networkClientId: NetworkClientId, options: Json): void;
102
+ /**
103
+ * Adds a callback to execute when polling is complete
104
+ *
105
+ * @param networkClientId - The networkClientId to listen for polling complete events
106
+ * @param callback - The callback to execute when polling is complete
107
+ * @param options - The options used to group the polling events
108
+ */
109
+ onPollingCompleteByNetworkClientId(networkClientId: NetworkClientId, callback: (networkClientId: NetworkClientId) => void, options?: Json): void;
110
+ }) & typeof BaseController;
111
+ export {};
112
+ //# sourceMappingURL=PollingController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PollingController.d.ts","sourceRoot":"","sources":["../src/PollingController.ts"],"names":[],"mappings":";;;;;AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAQ5C;;;;;GAKG;AACH,eAAO,MAAM,MAAM,oBACA,eAAe,WACvB,IAAI,KACZ,iBAA+D,CAAC;AAEnE,aAAK,iBAAiB,GAAG,GAAG,eAAe,IAAI,MAAM,EAAE,CAAC;AAoKxD,eAAO,MAAM,iBAAiB,0BAjLG,GAAG,EAAE;2CA4BN,IAAI,iBAAiB,EAAE,IAAI,MAAM,CAAC,CAAC;sCAExC,OAAO,iBAAiB,EAAE,OAAO,OAAO,CAAC;6DAIxC,eAAe,KAAK,IAAI;;;IAShD;;;;OAIG;8BACuB,MAAM;IAIhC;;;;;;OAMG;mDAEgB,eAAe,YACvB,IAAI;IAkBf;;OAEG;;IASH;;;;OAIG;4CACqC,MAAM;IAyB9C;;;;;OAKG;kCAEgB,eAAe,WACvB,IAAI,GACZ,QAAQ,IAAI,CAAC;sCAEO,eAAe,WAAW,IAAI;IAmBrD;;;;;;OAMG;wDAEgB,eAAe,8BACJ,eAAe,KAAK,IAAI,YAC3C,IAAI;4BAiBsD,CAAC;AAC1E,eAAO,MAAM,mBAAmB,0BAlLC,GAAG,EAAE;2CA4BN,IAAI,iBAAiB,EAAE,IAAI,MAAM,CAAC,CAAC;sCAExC,OAAO,iBAAiB,EAAE,OAAO,OAAO,CAAC;6DAIxC,eAAe,KAAK,IAAI;;;IAShD;;;;OAIG;8BACuB,MAAM;IAIhC;;;;;;OAMG;mDAEgB,eAAe,YACvB,IAAI;IAkBf;;OAEG;;IASH;;;;OAIG;4CACqC,MAAM;IAyB9C;;;;;OAKG;kCAEgB,eAAe,WACvB,IAAI,GACZ,QAAQ,IAAI,CAAC;sCAEO,eAAe,WAAW,IAAI;IAmBrD;;;;;;OAMG;wDAEgB,eAAe,8BACJ,eAAe,KAAK,IAAI,YAC3C,IAAI;0BAkBsD,CAAC"}
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
12
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
13
+ 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");
14
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
15
+ };
16
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
17
+ if (kind === "m") throw new TypeError("Private method is not writable");
18
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
19
+ 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");
20
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
21
+ };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.PollingControllerV1 = exports.PollingController = exports.getKey = void 0;
27
+ const base_controller_1 = require("@metamask/base-controller");
28
+ const fast_json_stable_stringify_1 = __importDefault(require("fast-json-stable-stringify"));
29
+ const uuid_1 = require("uuid");
30
+ /**
31
+ * Returns a unique key for a networkClientId and options. This is used to group networkClientId polls with the same options
32
+ * @param networkClientId - The networkClientId to get a key for
33
+ * @param options - The options used to group the polling events
34
+ * @returns The unique key
35
+ */
36
+ const getKey = (networkClientId, options) => `${networkClientId}:${(0, fast_json_stable_stringify_1.default)(options)}`;
37
+ exports.getKey = getKey;
38
+ /**
39
+ * PollingControllerMixin
40
+ *
41
+ * @param Base - The base class to mix onto.
42
+ * @returns The composed class.
43
+ */
44
+ function PollingControllerMixin(Base) {
45
+ var _PollingControllerBase_instances, _PollingControllerBase_pollingTokenSets, _PollingControllerBase_intervalIds, _PollingControllerBase_callbacks, _PollingControllerBase_intervalLength, _PollingControllerBase_poll;
46
+ /**
47
+ * PollingController is an abstract class that implements the polling
48
+ * functionality for a controller. It is meant to be extended by a controller
49
+ * that needs to poll for data by networkClientId.
50
+ *
51
+ */
52
+ class PollingControllerBase extends Base {
53
+ constructor() {
54
+ super(...arguments);
55
+ _PollingControllerBase_instances.add(this);
56
+ _PollingControllerBase_pollingTokenSets.set(this, new Map());
57
+ _PollingControllerBase_intervalIds.set(this, {});
58
+ _PollingControllerBase_callbacks.set(this, new Map());
59
+ _PollingControllerBase_intervalLength.set(this, 1000);
60
+ }
61
+ getIntervalLength() {
62
+ return __classPrivateFieldGet(this, _PollingControllerBase_intervalLength, "f");
63
+ }
64
+ /**
65
+ * Sets the length of the polling interval
66
+ *
67
+ * @param length - The length of the polling interval in milliseconds
68
+ */
69
+ setIntervalLength(length) {
70
+ __classPrivateFieldSet(this, _PollingControllerBase_intervalLength, length, "f");
71
+ }
72
+ /**
73
+ * Starts polling for a networkClientId
74
+ *
75
+ * @param networkClientId - The networkClientId to start polling for
76
+ * @param options - The options used to group the polling events
77
+ * @returns void
78
+ */
79
+ startPollingByNetworkClientId(networkClientId, options = {}) {
80
+ const pollToken = (0, uuid_1.v4)();
81
+ const key = (0, exports.getKey)(networkClientId, options);
82
+ const pollingTokenSet = __classPrivateFieldGet(this, _PollingControllerBase_pollingTokenSets, "f").get(key);
83
+ if (pollingTokenSet) {
84
+ pollingTokenSet.add(pollToken);
85
+ }
86
+ else {
87
+ const set = new Set();
88
+ set.add(pollToken);
89
+ __classPrivateFieldGet(this, _PollingControllerBase_pollingTokenSets, "f").set(key, set);
90
+ }
91
+ __classPrivateFieldGet(this, _PollingControllerBase_instances, "m", _PollingControllerBase_poll).call(this, networkClientId, options);
92
+ return pollToken;
93
+ }
94
+ /**
95
+ * Stops polling for all networkClientIds
96
+ */
97
+ stopAllPolling() {
98
+ __classPrivateFieldGet(this, _PollingControllerBase_pollingTokenSets, "f").forEach((tokenSet, _networkClientId) => {
99
+ tokenSet.forEach((token) => {
100
+ this.stopPollingByPollingToken(token);
101
+ });
102
+ });
103
+ }
104
+ /**
105
+ * Stops polling for a networkClientId
106
+ *
107
+ * @param pollingToken - The polling token to stop polling for
108
+ */
109
+ stopPollingByPollingToken(pollingToken) {
110
+ if (!pollingToken) {
111
+ throw new Error('pollingToken required');
112
+ }
113
+ let found = false;
114
+ __classPrivateFieldGet(this, _PollingControllerBase_pollingTokenSets, "f").forEach((tokenSet, key) => {
115
+ var _a, _b;
116
+ if (tokenSet.has(pollingToken)) {
117
+ found = true;
118
+ tokenSet.delete(pollingToken);
119
+ if (tokenSet.size === 0) {
120
+ clearTimeout(__classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key]);
121
+ delete __classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key];
122
+ __classPrivateFieldGet(this, _PollingControllerBase_pollingTokenSets, "f").delete(key);
123
+ (_a = __classPrivateFieldGet(this, _PollingControllerBase_callbacks, "f").get(key)) === null || _a === void 0 ? void 0 : _a.forEach((callback) => {
124
+ callback(key);
125
+ });
126
+ (_b = __classPrivateFieldGet(this, _PollingControllerBase_callbacks, "f").get(key)) === null || _b === void 0 ? void 0 : _b.clear();
127
+ }
128
+ }
129
+ });
130
+ if (!found) {
131
+ throw new Error('pollingToken not found');
132
+ }
133
+ }
134
+ /**
135
+ * Adds a callback to execute when polling is complete
136
+ *
137
+ * @param networkClientId - The networkClientId to listen for polling complete events
138
+ * @param callback - The callback to execute when polling is complete
139
+ * @param options - The options used to group the polling events
140
+ */
141
+ onPollingCompleteByNetworkClientId(networkClientId, callback, options = {}) {
142
+ const key = (0, exports.getKey)(networkClientId, options);
143
+ const callbacks = __classPrivateFieldGet(this, _PollingControllerBase_callbacks, "f").get(key);
144
+ if (callbacks === undefined) {
145
+ const set = new Set();
146
+ set.add(callback);
147
+ __classPrivateFieldGet(this, _PollingControllerBase_callbacks, "f").set(key, set);
148
+ }
149
+ else {
150
+ callbacks.add(callback);
151
+ }
152
+ }
153
+ }
154
+ _PollingControllerBase_pollingTokenSets = new WeakMap(), _PollingControllerBase_intervalIds = new WeakMap(), _PollingControllerBase_callbacks = new WeakMap(), _PollingControllerBase_intervalLength = new WeakMap(), _PollingControllerBase_instances = new WeakSet(), _PollingControllerBase_poll = function _PollingControllerBase_poll(networkClientId, options) {
155
+ const key = (0, exports.getKey)(networkClientId, options);
156
+ if (__classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key]) {
157
+ clearTimeout(__classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key]);
158
+ delete __classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key];
159
+ }
160
+ // setTimeout is not `await`ing this async function, which is expected
161
+ // We're just using async here for improved stack traces
162
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
163
+ __classPrivateFieldGet(this, _PollingControllerBase_intervalIds, "f")[key] = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
164
+ try {
165
+ yield this._executePoll(networkClientId, options);
166
+ }
167
+ catch (error) {
168
+ console.error(error);
169
+ }
170
+ __classPrivateFieldGet(this, _PollingControllerBase_instances, "m", _PollingControllerBase_poll).call(this, networkClientId, options);
171
+ }), __classPrivateFieldGet(this, _PollingControllerBase_intervalLength, "f"));
172
+ };
173
+ return PollingControllerBase;
174
+ }
175
+ exports.PollingController = PollingControllerMixin(base_controller_1.BaseControllerV2);
176
+ exports.PollingControllerV1 = PollingControllerMixin(base_controller_1.BaseController);
177
+ //# sourceMappingURL=PollingController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PollingController.js","sourceRoot":"","sources":["../src/PollingController.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+DAA6E;AAG7E,4FAAmD;AACnD,+BAAoC;AAMpC;;;;;GAKG;AACI,MAAM,MAAM,GAAG,CACpB,eAAgC,EAChC,OAAa,EACM,EAAE,CAAC,GAAG,eAAe,IAAI,IAAA,oCAAS,EAAC,OAAO,CAAC,EAAE,CAAC;AAHtD,QAAA,MAAM,UAGgD;AAGnE;;;;;GAKG;AACH,SAAS,sBAAsB,CAA4B,IAAW;;IACpE;;;;;OAKG;IACH,MAAe,qBAAsB,SAAQ,IAAI;QAAjD;;;YACE,kDAAkE,IAAI,GAAG,EAAE,EAAC;YAE5E,6CAAmE,EAAE,EAAC;YAEtE,2CAGI,IAAI,GAAG,EAAE,EAAC;YAEd,gDAAkB,IAAI,EAAC;QAwIzB,CAAC;QAtIC,iBAAiB;YACf,OAAO,uBAAA,IAAI,6CAAgB,CAAC;QAC9B,CAAC;QAED;;;;WAIG;QACH,iBAAiB,CAAC,MAAc;YAC9B,uBAAA,IAAI,yCAAmB,MAAM,MAAA,CAAC;QAChC,CAAC;QAED;;;;;;WAMG;QACH,6BAA6B,CAC3B,eAAgC,EAChC,UAAgB,EAAE;YAElB,MAAM,SAAS,GAAG,IAAA,SAAM,GAAE,CAAC;YAE3B,MAAM,GAAG,GAAG,IAAA,cAAM,EAAC,eAAe,EAAE,OAAO,CAAC,CAAC;YAE7C,MAAM,eAAe,GAAG,uBAAA,IAAI,+CAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACxD,IAAI,eAAe,EAAE;gBACnB,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;aAChC;iBAAM;gBACL,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;gBAC9B,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACnB,uBAAA,IAAI,+CAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aACtC;YACD,uBAAA,IAAI,qEAAM,MAAV,IAAI,EAAO,eAAe,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED;;WAEG;QACH,cAAc;YACZ,uBAAA,IAAI,+CAAkB,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,gBAAgB,EAAE,EAAE;gBAC5D,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;oBACzB,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;gBACxC,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED;;;;WAIG;QACH,yBAAyB,CAAC,YAAoB;YAC5C,IAAI,CAAC,YAAY,EAAE;gBACjB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;aAC1C;YACD,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,uBAAA,IAAI,+CAAkB,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;;gBAC/C,IAAI,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;oBAC9B,KAAK,GAAG,IAAI,CAAC;oBACb,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;oBAC9B,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE;wBACvB,YAAY,CAAC,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,CAAC,CAAC;wBACrC,OAAO,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,CAAC;wBAC9B,uBAAA,IAAI,+CAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;wBACnC,MAAA,uBAAA,IAAI,wCAAW,CAAC,GAAG,CAAC,GAAG,CAAC,0CAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;4BAC7C,QAAQ,CAAC,GAAG,CAAC,CAAC;wBAChB,CAAC,CAAC,CAAC;wBACH,MAAA,uBAAA,IAAI,wCAAW,CAAC,GAAG,CAAC,GAAG,CAAC,0CAAE,KAAK,EAAE,CAAC;qBACnC;iBACF;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,EAAE;gBACV,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;aAC3C;QACH,CAAC;QAgCD;;;;;;WAMG;QACH,kCAAkC,CAChC,eAAgC,EAChC,QAAoD,EACpD,UAAgB,EAAE;YAElB,MAAM,GAAG,GAAG,IAAA,cAAM,EAAC,eAAe,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,SAAS,GAAG,uBAAA,IAAI,wCAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAE3C,IAAI,SAAS,KAAK,SAAS,EAAE;gBAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmB,CAAC;gBACvC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAClB,uBAAA,IAAI,wCAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aAC/B;iBAAM;gBACL,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;aACzB;QACH,CAAC;KACF;+UA1CO,eAAgC,EAAE,OAAa;QACnD,MAAM,GAAG,GAAG,IAAA,cAAM,EAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAC7C,IAAI,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,EAAE;YAC1B,YAAY,CAAC,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,OAAO,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,CAAC;SAC/B;QACD,sEAAsE;QACtE,wDAAwD;QACxD,kEAAkE;QAClE,uBAAA,IAAI,0CAAa,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,GAAS,EAAE;YAC7C,IAAI;gBACF,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;aACnD;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aACtB;YACD,uBAAA,IAAI,qEAAM,MAAV,IAAI,EAAO,eAAe,EAAE,OAAO,CAAC,CAAC;QACvC,CAAC,CAAA,EAAE,uBAAA,IAAI,6CAAgB,CAAC,CAAC;IAC3B,CAAC;IA0BH,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAEY,QAAA,iBAAiB,GAAG,sBAAsB,CAAC,kCAAgB,CAAC,CAAC;AAC7D,QAAA,mBAAmB,GAAG,sBAAsB,CAAC,gCAAc,CAAC,CAAC","sourcesContent":["import { BaseController, BaseControllerV2 } from '@metamask/base-controller';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Json } from '@metamask/utils';\nimport stringify from 'fast-json-stable-stringify';\nimport { v4 as random } from 'uuid';\n\n// Mixin classes require a constructor with an `...any[]` parameter\n// See TS2545\ntype Constructor = new (...args: any[]) => object;\n\n/**\n * Returns a unique key for a networkClientId and options. This is used to group networkClientId polls with the same options\n * @param networkClientId - The networkClientId to get a key for\n * @param options - The options used to group the polling events\n * @returns The unique key\n */\nexport const getKey = (\n networkClientId: NetworkClientId,\n options: Json,\n): PollingTokenSetId => `${networkClientId}:${stringify(options)}`;\n\ntype PollingTokenSetId = `${NetworkClientId}:${string}`;\n/**\n * PollingControllerMixin\n *\n * @param Base - The base class to mix onto.\n * @returns The composed class.\n */\nfunction PollingControllerMixin<TBase extends Constructor>(Base: TBase) {\n /**\n * PollingController is an abstract class that implements the polling\n * functionality for a controller. It is meant to be extended by a controller\n * that needs to poll for data by networkClientId.\n *\n */\n abstract class PollingControllerBase extends Base {\n readonly #pollingTokenSets: Map<PollingTokenSetId, Set<string>> = new Map();\n\n readonly #intervalIds: Record<PollingTokenSetId, NodeJS.Timeout> = {};\n\n #callbacks: Map<\n NetworkClientId,\n Set<(networkClientId: NetworkClientId) => void>\n > = new Map();\n\n #intervalLength = 1000;\n\n getIntervalLength() {\n return this.#intervalLength;\n }\n\n /**\n * Sets the length of the polling interval\n *\n * @param length - The length of the polling interval in milliseconds\n */\n setIntervalLength(length: number) {\n this.#intervalLength = length;\n }\n\n /**\n * Starts polling for a networkClientId\n *\n * @param networkClientId - The networkClientId to start polling for\n * @param options - The options used to group the polling events\n * @returns void\n */\n startPollingByNetworkClientId(\n networkClientId: NetworkClientId,\n options: Json = {},\n ) {\n const pollToken = random();\n\n const key = getKey(networkClientId, options);\n\n const pollingTokenSet = this.#pollingTokenSets.get(key);\n if (pollingTokenSet) {\n pollingTokenSet.add(pollToken);\n } else {\n const set = new Set<string>();\n set.add(pollToken);\n this.#pollingTokenSets.set(key, set);\n }\n this.#poll(networkClientId, options);\n return pollToken;\n }\n\n /**\n * Stops polling for all networkClientIds\n */\n stopAllPolling() {\n this.#pollingTokenSets.forEach((tokenSet, _networkClientId) => {\n tokenSet.forEach((token) => {\n this.stopPollingByPollingToken(token);\n });\n });\n }\n\n /**\n * Stops polling for a networkClientId\n *\n * @param pollingToken - The polling token to stop polling for\n */\n stopPollingByPollingToken(pollingToken: string) {\n if (!pollingToken) {\n throw new Error('pollingToken required');\n }\n let found = false;\n this.#pollingTokenSets.forEach((tokenSet, key) => {\n if (tokenSet.has(pollingToken)) {\n found = true;\n tokenSet.delete(pollingToken);\n if (tokenSet.size === 0) {\n clearTimeout(this.#intervalIds[key]);\n delete this.#intervalIds[key];\n this.#pollingTokenSets.delete(key);\n this.#callbacks.get(key)?.forEach((callback) => {\n callback(key);\n });\n this.#callbacks.get(key)?.clear();\n }\n }\n });\n if (!found) {\n throw new Error('pollingToken not found');\n }\n }\n\n /**\n * Executes the poll for a networkClientId\n *\n * @param networkClientId - The networkClientId to execute the poll for\n * @param options - The options passed to startPollingByNetworkClientId\n */\n abstract _executePoll(\n networkClientId: NetworkClientId,\n options: Json,\n ): Promise<void>;\n\n #poll(networkClientId: NetworkClientId, options: Json) {\n const key = getKey(networkClientId, options);\n if (this.#intervalIds[key]) {\n clearTimeout(this.#intervalIds[key]);\n delete this.#intervalIds[key];\n }\n // setTimeout is not `await`ing this async function, which is expected\n // We're just using async here for improved stack traces\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#intervalIds[key] = setTimeout(async () => {\n try {\n await this._executePoll(networkClientId, options);\n } catch (error) {\n console.error(error);\n }\n this.#poll(networkClientId, options);\n }, this.#intervalLength);\n }\n\n /**\n * Adds a callback to execute when polling is complete\n *\n * @param networkClientId - The networkClientId to listen for polling complete events\n * @param callback - The callback to execute when polling is complete\n * @param options - The options used to group the polling events\n */\n onPollingCompleteByNetworkClientId(\n networkClientId: NetworkClientId,\n callback: (networkClientId: NetworkClientId) => void,\n options: Json = {},\n ) {\n const key = getKey(networkClientId, options);\n const callbacks = this.#callbacks.get(key);\n\n if (callbacks === undefined) {\n const set = new Set<typeof callback>();\n set.add(callback);\n this.#callbacks.set(key, set);\n } else {\n callbacks.add(callback);\n }\n }\n }\n return PollingControllerBase;\n}\n\nexport const PollingController = PollingControllerMixin(BaseControllerV2);\nexport const PollingControllerV1 = PollingControllerMixin(BaseController);\n"]}
@@ -0,0 +1,2 @@
1
+ export { PollingController, PollingControllerV1 } from './PollingController';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PollingControllerV1 = exports.PollingController = void 0;
4
+ var PollingController_1 = require("./PollingController");
5
+ Object.defineProperty(exports, "PollingController", { enumerable: true, get: function () { return PollingController_1.PollingController; } });
6
+ Object.defineProperty(exports, "PollingControllerV1", { enumerable: true, get: function () { return PollingController_1.PollingControllerV1; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yDAA6E;AAApE,sHAAA,iBAAiB,OAAA;AAAE,wHAAA,mBAAmB,OAAA","sourcesContent":["export { PollingController, PollingControllerV1 } from './PollingController';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/polling-controller",
3
- "version": "0.0.0",
3
+ "version": "0.2.0",
4
4
  "description": "Polling Controller is the base for controllers that polling by networkClientId",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -25,14 +25,16 @@
25
25
  "changelog:validate": "../../scripts/validate-changelog.sh @metamask/polling-controller",
26
26
  "publish:preview": "yarn npm publish --tag preview",
27
27
  "test": "jest",
28
+ "test:clean": "jest --clearCache",
28
29
  "test:watch": "jest --watch"
29
30
  },
30
31
  "dependencies": {
31
- "@metamask/base-controller": "^3.2.2",
32
- "@metamask/controller-utils": "^5.0.1",
33
- "@metamask/network-controller": "^13.0.1",
34
- "@metamask/utils": "^6.2.0",
32
+ "@metamask/base-controller": "^3.2.3",
33
+ "@metamask/controller-utils": "^5.0.2",
34
+ "@metamask/network-controller": "^15.0.0",
35
+ "@metamask/utils": "^8.1.0",
35
36
  "@types/uuid": "^8.3.0",
37
+ "fast-json-stable-stringify": "^2.1.0",
36
38
  "uuid": "^8.3.2"
37
39
  },
38
40
  "devDependencies": {
@@ -41,12 +43,12 @@
41
43
  "deepmerge": "^4.2.2",
42
44
  "jest": "^27.5.1",
43
45
  "ts-jest": "^27.1.4",
44
- "typedoc": "^0.23.15",
45
- "typedoc-plugin-missing-exports": "^0.23.0",
46
+ "typedoc": "^0.24.8",
47
+ "typedoc-plugin-missing-exports": "^2.0.0",
46
48
  "typescript": "~4.8.4"
47
49
  },
48
50
  "peerDependencies": {
49
- "@metamask/network-controller": "^13.0.1"
51
+ "@metamask/network-controller": "^15.0.0"
50
52
  },
51
53
  "engines": {
52
54
  "node": ">=16.0.0"