webextension-messages 1.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/package.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "webextension-messages",
3
+ "version": "1.0.0",
4
+ "description": "Package simplifying the exchange of messages between the background and tabs",
5
+ "license": "MIT",
6
+ "author": "Igor Morozov",
7
+ "main": "webextension-messages.js",
8
+ "devDependencies": {
9
+ "webextension-polyfill": "0.12.0"
10
+ }
11
+ }
@@ -0,0 +1,91 @@
1
+ const browser = require("webextension-polyfill");
2
+
3
+ const DESTROY_ACTION = `WEBEXTENSION_MESSAGES_DESTROY`;
4
+ const RESULT_PROMISES = {};
5
+ const ACTIONS = {};
6
+
7
+ browser.runtime.onMessage.addListener((message) => {
8
+ if (message.action === DESTROY_ACTION) {
9
+ destroy(message.payload);
10
+ }
11
+ });
12
+
13
+ export default function (actions, messagesId = generateId()) {
14
+ const messages = Object.fromEntries(
15
+ Object.entries(actions).map(([action]) => [
16
+ action,
17
+ (payload) => sendMessageForAnswer(action, payload),
18
+ ]),
19
+ );
20
+
21
+ ACTIONS[messagesId] = (message) => onMessage(message, actions);
22
+
23
+ browser.runtime.onMessage.addListener(ACTIONS[messagesId]);
24
+
25
+ return {
26
+ ...messages,
27
+ destroy: () => destroy(messagesId, true),
28
+ };
29
+ }
30
+
31
+ async function onMessage(message, actions = {}) {
32
+ if (RESULT_PROMISES[message.resultId]) {
33
+ RESULT_PROMISES[message.resultId](message.payload);
34
+ delete RESULT_PROMISES[message.resultId];
35
+ return;
36
+ }
37
+
38
+ if (actions[message.action]) {
39
+ const payload = await actions[message.action](message.payload);
40
+ sendMessage(message.action, payload, message.resultId);
41
+ }
42
+ }
43
+
44
+ function sendMessageForAnswer(action, payload) {
45
+ const { resultId, promise } = createResultPromise();
46
+ sendMessage(action, payload, resultId);
47
+ return promise;
48
+ }
49
+
50
+ function sendMessage(action, payload, resultId) {
51
+ const message = { action, payload, resultId };
52
+
53
+ if (isBackgroundScript()) {
54
+ getCurrentTab().then((tab) => browser.tabs.sendMessage(tab[0].id, message));
55
+ } else {
56
+ browser.runtime.sendMessage(message);
57
+ }
58
+ }
59
+
60
+ function createResultPromise() {
61
+ const resultId = generateId();
62
+
63
+ return {
64
+ promise: new Promise((res) => (RESULT_PROMISES[resultId] = res)),
65
+ resultId,
66
+ };
67
+ }
68
+
69
+ function isBackgroundScript() {
70
+ return (
71
+ window.location.protocol === "chrome-extension:" ||
72
+ window.location.protocol === "moz-extension:"
73
+ );
74
+ }
75
+
76
+ function generateId() {
77
+ return `${Date.now()}-${Math.random()}`;
78
+ }
79
+
80
+ function getCurrentTab() {
81
+ return browser.tabs.query({ active: true, currentWindow: true });
82
+ }
83
+
84
+ function destroy(messagesId, sendToReceiver) {
85
+ browser.runtime.onMessage.removeListener(ACTIONS[messagesId]);
86
+ delete ACTIONS[messagesId];
87
+
88
+ if (sendToReceiver) {
89
+ sendMessage(DESTROY_ACTION, messagesId);
90
+ }
91
+ }