webext-messenger 0.31.0 → 0.32.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/distribution/logging.js
CHANGED
package/distribution/receiver.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import browser from "webextension-polyfill";
|
2
1
|
import { serializeError } from "serialize-error";
|
3
2
|
import { getContextName } from "webext-detect";
|
4
3
|
import { messenger } from "./sender.js";
|
@@ -13,8 +12,14 @@ export function isMessengerMessage(message) {
|
|
13
12
|
message["__webextMessenger"] === true &&
|
14
13
|
Array.isArray(message["args"]));
|
15
14
|
}
|
16
|
-
|
17
|
-
|
15
|
+
/**
|
16
|
+
* Decides what to do with a message and sends a response (value or error) back to the sender.
|
17
|
+
*
|
18
|
+
* @warn This function cannot return a Promise.
|
19
|
+
* @warn Limit the amount of logic here because errors won't make it to `sendResponse`
|
20
|
+
*/
|
21
|
+
//
|
22
|
+
function onMessageListener(message, sender, sendResponse) {
|
18
23
|
if (!isMessengerMessage(message)) {
|
19
24
|
// TODO: Add test for this eventuality: ignore unrelated messages
|
20
25
|
return;
|
@@ -29,21 +34,10 @@ function onMessageListener(message, sender) {
|
|
29
34
|
});
|
30
35
|
return;
|
31
36
|
}
|
32
|
-
return handleMessage(message, sender, action);
|
33
|
-
}
|
34
|
-
// This function can only be called when the message *will* be handled locally.
|
35
|
-
// Returning "undefined" or throwing an error will still handle it.
|
36
|
-
async function handleMessage(message, sender,
|
37
|
-
// Once messages reach this function they cannot be "ignored", they're already being handled
|
38
|
-
action) {
|
39
37
|
const { type, target, args, options = {} } = message;
|
40
38
|
const { trace = [], seq } = options;
|
41
|
-
trace.push(sender);
|
42
|
-
const meta = { trace };
|
43
|
-
let handleMessage;
|
44
39
|
if (action === "forward") {
|
45
40
|
log.debug(type, seq, "🔀 forwarded", { sender, target });
|
46
|
-
handleMessage = async () => messenger(type, meta, target, ...args);
|
47
41
|
}
|
48
42
|
else {
|
49
43
|
log.debug(type, seq, "↘️ received in", getContextName(), {
|
@@ -51,24 +45,40 @@ action) {
|
|
51
45
|
args,
|
52
46
|
wasForwarded: trace.length > 1,
|
53
47
|
});
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
}
|
61
|
-
|
48
|
+
}
|
49
|
+
// Prepare the response asynchronously because the listener must return `true` synchronously
|
50
|
+
(async () => {
|
51
|
+
try {
|
52
|
+
trace.push(sender);
|
53
|
+
const value = await prepareResponse(message, action, { trace });
|
54
|
+
log.debug(type, seq, "↗️ responding", { value });
|
55
|
+
sendResponse({ __webextMessenger, value });
|
62
56
|
}
|
63
|
-
|
57
|
+
catch (error) {
|
58
|
+
log.debug(type, seq, "↗️ responding", { error });
|
59
|
+
sendResponse({ __webextMessenger, error: serializeError(error) });
|
60
|
+
}
|
61
|
+
})();
|
62
|
+
// This indicates that the message is being handled and a response will be sent asynchronously
|
63
|
+
// TODO: Just return a promise if this is ever implemented https://issues.chromium.org/issues/40753031
|
64
|
+
return true;
|
65
|
+
}
|
66
|
+
/** Generates the value or error to return to the sender; does not include further messaging logic */
|
67
|
+
async function prepareResponse(message, action, meta) {
|
68
|
+
const { type, target, args } = message;
|
69
|
+
if (action === "forward") {
|
70
|
+
return messenger(type, meta, target, ...args);
|
71
|
+
}
|
72
|
+
const localHandler = handlers.get(type);
|
73
|
+
if (localHandler) {
|
74
|
+
return localHandler.apply(meta, args);
|
75
|
+
}
|
76
|
+
if (didUserRegisterMethods()) {
|
77
|
+
throw new MessengerError(`No handler registered for ${type} in ${getContextName()}`);
|
64
78
|
}
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
error: serializeError(error),
|
69
|
-
}));
|
70
|
-
log.debug(type, seq, "↗️ responding", response);
|
71
|
-
return { ...response, __webextMessenger };
|
79
|
+
// TODO: Test the handling of __getTabData in contexts that have no registered methods
|
80
|
+
// https://github.com/pixiebrix/webext-messenger/pull/82
|
81
|
+
throw new MessengerError(`No handlers registered in ${getContextName()}`);
|
72
82
|
}
|
73
83
|
export function registerMethods(methods) {
|
74
84
|
for (const [type, method] of Object.entries(methods)) {
|
@@ -78,7 +88,7 @@ export function registerMethods(methods) {
|
|
78
88
|
log.debug("Registered", type);
|
79
89
|
handlers.set(type, method);
|
80
90
|
}
|
81
|
-
|
91
|
+
chrome.runtime.onMessage.addListener(onMessageListener);
|
82
92
|
}
|
83
93
|
/** Ensure/document that the current function was called via Messenger */
|
84
94
|
export function assertMessengerCall(_this) { }
|
package/distribution/sender.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import browser from "webextension-polyfill";
|
2
1
|
import pRetry from "p-retry";
|
3
2
|
import { isBackground } from "webext-detect";
|
4
3
|
import { deserializeError } from "serialize-error";
|
@@ -7,7 +6,6 @@ import { log } from "./logging.js";
|
|
7
6
|
import { handlers } from "./handlers.js";
|
8
7
|
import { events } from "./events.js";
|
9
8
|
const _errorNonExistingTarget = "Could not establish connection. Receiving end does not exist.";
|
10
|
-
// https://github.com/mozilla/webextension-polyfill/issues/384
|
11
9
|
const _errorTargetClosedEarly = "A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received";
|
12
10
|
export const errorTargetClosedEarly = "The target was closed before receiving a response";
|
13
11
|
export const errorTabDoesntExist = "The tab doesn't exist";
|
@@ -100,9 +98,9 @@ async function manageMessage(type, target, seq, retry, sendMessage) {
|
|
100
98
|
String(error.message).startsWith("No handlers registered in ")))) {
|
101
99
|
throw error;
|
102
100
|
}
|
103
|
-
if (
|
101
|
+
if (chrome.tabs && typeof target.tabId === "number") {
|
104
102
|
try {
|
105
|
-
const tabInfo = await
|
103
|
+
const tabInfo = await chrome.tabs.get(target.tabId);
|
106
104
|
if (tabInfo.discarded) {
|
107
105
|
throw new Error(errorTabWasDiscarded);
|
108
106
|
}
|
@@ -155,15 +153,15 @@ function messenger(type, options, target, ...args) {
|
|
155
153
|
}
|
156
154
|
const sendMessage = async (attemptCount) => {
|
157
155
|
log.debug(type, seq, "↗️ sending message to runtime", attemptLog(attemptCount));
|
158
|
-
return
|
156
|
+
return chrome.runtime.sendMessage(makeMessage(type, args, target, options));
|
159
157
|
};
|
160
158
|
return manageConnection(type, options, target, sendMessage);
|
161
159
|
}
|
162
160
|
// Contexts without direct Tab access must go through background
|
163
|
-
if (!
|
161
|
+
if (!chrome.tabs) {
|
164
162
|
return manageConnection(type, options, target, async (attemptCount) => {
|
165
163
|
log.debug(type, seq, "↗️ sending message to runtime", attemptLog(attemptCount));
|
166
|
-
return
|
164
|
+
return chrome.runtime.sendMessage(makeMessage(type, args, target, options));
|
167
165
|
});
|
168
166
|
}
|
169
167
|
// `frameId` must be specified. If missing, the message is sent to every frame
|
@@ -171,7 +169,7 @@ function messenger(type, options, target, ...args) {
|
|
171
169
|
// Message tab directly
|
172
170
|
return manageConnection(type, options, target, async (attemptCount) => {
|
173
171
|
log.debug(type, seq, "↗️ sending message to tab", tabId, "frame", frameId, attemptLog(attemptCount));
|
174
|
-
return
|
172
|
+
return chrome.tabs.sendMessage(tabId, makeMessage(type, args, target, options), frameId === "allFrames"
|
175
173
|
? {}
|
176
174
|
: {
|
177
175
|
frameId,
|
package/distribution/types.d.ts
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import { type Runtime } from "webextension-polyfill";
|
2
1
|
import { type Asyncify, type ValueOf } from "type-fest";
|
3
2
|
import { type ErrorObject } from "serialize-error";
|
4
3
|
/**
|
@@ -48,9 +47,7 @@ export type Message<LocalArguments extends Arguments = Arguments> = {
|
|
48
47
|
/** If the message is being sent to an intermediary receiver, also set the options */
|
49
48
|
options?: Options;
|
50
49
|
};
|
51
|
-
export type Sender =
|
52
|
-
origin?: string;
|
53
|
-
};
|
50
|
+
export type Sender = chrome.runtime.MessageSender;
|
54
51
|
export type MessengerMessage = Message & {
|
55
52
|
/** Guarantees that a message is meant to be handled by this library */
|
56
53
|
__webextMessenger: true;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "webext-messenger",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.32.0",
|
4
4
|
"description": "Browser Extension component messaging framework",
|
5
5
|
"keywords": [],
|
6
6
|
"repository": "pixiebrix/webext-messenger",
|
@@ -29,9 +29,8 @@
|
|
29
29
|
"p-event": "^6.0.1",
|
30
30
|
"p-retry": "^6.2.1",
|
31
31
|
"serialize-error": "^12.0.0",
|
32
|
-
"type-fest": "^4.
|
33
|
-
"webext-detect": "^5.3.2"
|
34
|
-
"webext-events": "^3.1.1"
|
32
|
+
"type-fest": "^4.36.0",
|
33
|
+
"webext-detect": "^5.3.2"
|
35
34
|
},
|
36
35
|
"@parcel/resolver-default": {
|
37
36
|
"packageExports": true
|
@@ -39,9 +38,8 @@
|
|
39
38
|
"devDependencies": {
|
40
39
|
"@parcel/config-webextension": "^2.11.0",
|
41
40
|
"@sindresorhus/tsconfig": "^7.0.0",
|
42
|
-
"@types/chrome": "^0.0.
|
41
|
+
"@types/chrome": "^0.0.307",
|
43
42
|
"@types/tape": "^5.8.1",
|
44
|
-
"@types/webextension-polyfill": "^0.12.1",
|
45
43
|
"buffer": "^6.0.3",
|
46
44
|
"eslint": "^8.57.0",
|
47
45
|
"eslint-config-pixiebrix": "^0.41.1",
|
@@ -52,10 +50,8 @@
|
|
52
50
|
"process": "^0.11.10",
|
53
51
|
"stream-browserify": "^3.0.0",
|
54
52
|
"tape": "^5.9.0",
|
55
|
-
"typescript": "^5.
|
56
|
-
"vitest": "^3.0.
|
57
|
-
"webext-content-scripts": "^2.7.2",
|
58
|
-
"webextension-polyfill": "^0.12.0"
|
53
|
+
"typescript": "^5.8.2",
|
54
|
+
"vitest": "^3.0.7"
|
59
55
|
},
|
60
56
|
"targets": {
|
61
57
|
"main": false,
|