webext-messenger 0.30.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.
@@ -1,4 +1,3 @@
1
- /* Warning: Do not use import browser-polyfill directly or indirectly */
2
1
  // .bind preserves the call location in the console
3
2
  const debug = console.debug.bind(console, "Messenger:");
4
3
  const warn = console.warn.bind(console, "Messenger:");
@@ -12,8 +12,14 @@ export function isMessengerMessage(message) {
12
12
  message["__webextMessenger"] === true &&
13
13
  Array.isArray(message["args"]));
14
14
  }
15
- // MUST NOT be `async` or Promise-returning-only
16
- function onMessageListener(message, sender) {
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) {
17
23
  if (!isMessengerMessage(message)) {
18
24
  // TODO: Add test for this eventuality: ignore unrelated messages
19
25
  return;
@@ -28,21 +34,10 @@ function onMessageListener(message, sender) {
28
34
  });
29
35
  return;
30
36
  }
31
- return handleMessage(message, sender, action);
32
- }
33
- // This function can only be called when the message *will* be handled locally.
34
- // Returning "undefined" or throwing an error will still handle it.
35
- async function handleMessage(message, sender,
36
- // Once messages reach this function they cannot be "ignored", they're already being handled
37
- action) {
38
37
  const { type, target, args, options = {} } = message;
39
38
  const { trace = [], seq } = options;
40
- trace.push(sender);
41
- const meta = { trace };
42
- let handleMessage;
43
39
  if (action === "forward") {
44
40
  log.debug(type, seq, "🔀 forwarded", { sender, target });
45
- handleMessage = async () => messenger(type, meta, target, ...args);
46
41
  }
47
42
  else {
48
43
  log.debug(type, seq, "↘️ received in", getContextName(), {
@@ -50,24 +45,40 @@ action) {
50
45
  args,
51
46
  wasForwarded: trace.length > 1,
52
47
  });
53
- const localHandler = handlers.get(type);
54
- if (!localHandler) {
55
- if (!didUserRegisterMethods()) {
56
- // TODO: Test the handling of __getTabData in contexts that have no registered methods
57
- // https://github.com/pixiebrix/webext-messenger/pull/82
58
- throw new MessengerError(`No handlers registered in ${getContextName()}`);
59
- }
60
- throw new MessengerError(`No handler registered for ${type} in ${getContextName()}`);
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 });
61
56
  }
62
- handleMessage = async () => localHandler.apply(meta, args);
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()}`);
63
78
  }
64
- const response = await handleMessage().then((value) => ({ value }), (error) => ({
65
- // Errors must be serialized because the stack traces are currently lost on Chrome
66
- // and https://github.com/mozilla/webextension-polyfill/issues/210
67
- error: serializeError(error),
68
- }));
69
- log.debug(type, seq, "↗️ responding", response);
70
- 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()}`);
71
82
  }
72
83
  export function registerMethods(methods) {
73
84
  for (const [type, method] of Object.entries(methods)) {
@@ -77,7 +88,7 @@ export function registerMethods(methods) {
77
88
  log.debug("Registered", type);
78
89
  handlers.set(type, method);
79
90
  }
80
- browser.runtime.onMessage.addListener(onMessageListener);
91
+ chrome.runtime.onMessage.addListener(onMessageListener);
81
92
  }
82
93
  /** Ensure/document that the current function was called via Messenger */
83
94
  export function assertMessengerCall(_this) { }
@@ -6,7 +6,6 @@ import { log } from "./logging.js";
6
6
  import { handlers } from "./handlers.js";
7
7
  import { events } from "./events.js";
8
8
  const _errorNonExistingTarget = "Could not establish connection. Receiving end does not exist.";
9
- // https://github.com/mozilla/webextension-polyfill/issues/384
10
9
  const _errorTargetClosedEarly = "A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received";
11
10
  export const errorTargetClosedEarly = "The target was closed before receiving a response";
12
11
  export const errorTabDoesntExist = "The tab doesn't exist";
@@ -99,9 +98,9 @@ async function manageMessage(type, target, seq, retry, sendMessage) {
99
98
  String(error.message).startsWith("No handlers registered in ")))) {
100
99
  throw error;
101
100
  }
102
- if (browser.tabs && typeof target.tabId === "number") {
101
+ if (chrome.tabs && typeof target.tabId === "number") {
103
102
  try {
104
- const tabInfo = await browser.tabs.get(target.tabId);
103
+ const tabInfo = await chrome.tabs.get(target.tabId);
105
104
  if (tabInfo.discarded) {
106
105
  throw new Error(errorTabWasDiscarded);
107
106
  }
@@ -154,15 +153,15 @@ function messenger(type, options, target, ...args) {
154
153
  }
155
154
  const sendMessage = async (attemptCount) => {
156
155
  log.debug(type, seq, "↗️ sending message to runtime", attemptLog(attemptCount));
157
- return browser.runtime.sendMessage(makeMessage(type, args, target, options));
156
+ return chrome.runtime.sendMessage(makeMessage(type, args, target, options));
158
157
  };
159
158
  return manageConnection(type, options, target, sendMessage);
160
159
  }
161
160
  // Contexts without direct Tab access must go through background
162
- if (!browser.tabs) {
161
+ if (!chrome.tabs) {
163
162
  return manageConnection(type, options, target, async (attemptCount) => {
164
163
  log.debug(type, seq, "↗️ sending message to runtime", attemptLog(attemptCount));
165
- return browser.runtime.sendMessage(makeMessage(type, args, target, options));
164
+ return chrome.runtime.sendMessage(makeMessage(type, args, target, options));
166
165
  });
167
166
  }
168
167
  // `frameId` must be specified. If missing, the message is sent to every frame
@@ -170,7 +169,7 @@ function messenger(type, options, target, ...args) {
170
169
  // Message tab directly
171
170
  return manageConnection(type, options, target, async (attemptCount) => {
172
171
  log.debug(type, seq, "↗️ sending message to tab", tabId, "frame", frameId, attemptLog(attemptCount));
173
- return browser.tabs.sendMessage(tabId, makeMessage(type, args, target, options), frameId === "allFrames"
172
+ return chrome.tabs.sendMessage(tabId, makeMessage(type, args, target, options), frameId === "allFrames"
174
173
  ? {}
175
174
  : {
176
175
  frameId,
@@ -11,6 +11,11 @@ const tab = {
11
11
  pinned: false,
12
12
  highlighted: true,
13
13
  incognito: false,
14
+ discarded: false,
15
+ frozen: false,
16
+ selected: true,
17
+ autoDiscardable: false,
18
+ groupId: -1,
14
19
  };
15
20
  const senders = {
16
21
  background: { page: "background" },
@@ -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 = Runtime.MessageSender & {
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.30.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.31.0",
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.287",
43
- "@types/tape": "^5.8.0",
44
- "@types/webextension-polyfill": "^0.12.1",
41
+ "@types/chrome": "^0.0.307",
42
+ "@types/tape": "^5.8.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.7.2",
56
- "vitest": "^2.1.8",
57
- "webext-content-scripts": "^2.7.0",
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,