webext-messenger 0.22.0 โ 0.23.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/index.d.ts +1 -0
- package/distribution/index.js +1 -0
- package/distribution/receiver.d.ts +3 -1
- package/distribution/receiver.js +10 -6
- package/distribution/sender.js +25 -19
- package/distribution/shared.d.ts +5 -2
- package/distribution/shared.js +12 -14
- package/distribution/thisTarget.js +2 -2
- package/distribution/types.d.ts +3 -1
- package/package.json +18 -18
- package/readme.md +7 -2
package/distribution/index.d.ts
CHANGED
package/distribution/index.js
CHANGED
|
@@ -3,5 +3,6 @@ export * from "./receiver.js";
|
|
|
3
3
|
export * from "./sender.js";
|
|
4
4
|
export * from "./types.js";
|
|
5
5
|
export { getThisFrame, getTopLevelFrame } from "./thisTarget.js";
|
|
6
|
+
export { toggleLogging } from "./shared.js";
|
|
6
7
|
import { initPrivateApi } from "./thisTarget.js";
|
|
7
8
|
initPrivateApi();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import { type Message } from "./types.js";
|
|
1
|
+
import { type Message, type MessengerMeta } from "./types.js";
|
|
2
2
|
export declare function isMessengerMessage(message: unknown): message is Message;
|
|
3
3
|
export declare function registerMethods(methods: Partial<MessengerMethods>): void;
|
|
4
|
+
/** Ensure/document that the current function was called via Messenger */
|
|
5
|
+
export declare function assertMessengerCall(_this: MessengerMeta): asserts _this is MessengerMeta;
|
package/distribution/receiver.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { serializeError } from "serialize-error";
|
|
2
2
|
import { getContextName } from "webext-detect-page";
|
|
3
3
|
import { messenger } from "./sender.js";
|
|
4
|
-
import { isObject, MessengerError,
|
|
4
|
+
import { isObject, MessengerError, log, __webextMessenger } from "./shared.js";
|
|
5
5
|
import { getActionForMessage } from "./thisTarget.js";
|
|
6
6
|
import { didUserRegisterMethods, handlers } from "./handlers.js";
|
|
7
7
|
export function isMessengerMessage(message) {
|
|
@@ -29,16 +29,16 @@ async function handleMessage(message, sender,
|
|
|
29
29
|
// Once messages reach this function they cannot be "ignored", they're already being handled
|
|
30
30
|
action) {
|
|
31
31
|
const { type, target, args, options = {} } = message;
|
|
32
|
-
const { trace = [] } = options;
|
|
32
|
+
const { trace = [], seq } = options;
|
|
33
33
|
trace.push(sender);
|
|
34
34
|
const meta = { trace };
|
|
35
35
|
let handleMessage;
|
|
36
36
|
if (action === "forward") {
|
|
37
|
-
debug(type, "๐ forwarded", { sender, target });
|
|
37
|
+
log.debug(type, seq, "๐ forwarded", { sender, target });
|
|
38
38
|
handleMessage = async () => messenger(type, meta, target, ...args);
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
debug(type, "โ๏ธ received in", getContextName(), {
|
|
41
|
+
log.debug(type, seq, "โ๏ธ received in", getContextName(), {
|
|
42
42
|
sender,
|
|
43
43
|
args,
|
|
44
44
|
wasForwarded: trace.length > 1,
|
|
@@ -59,7 +59,7 @@ action) {
|
|
|
59
59
|
// and https://github.com/mozilla/webextension-polyfill/issues/210
|
|
60
60
|
error: serializeError(error),
|
|
61
61
|
}));
|
|
62
|
-
debug(type, "โ๏ธ responding", response);
|
|
62
|
+
log.debug(type, seq, "โ๏ธ responding", response);
|
|
63
63
|
return { ...response, __webextMessenger };
|
|
64
64
|
}
|
|
65
65
|
export function registerMethods(methods) {
|
|
@@ -67,8 +67,12 @@ export function registerMethods(methods) {
|
|
|
67
67
|
if (handlers.has(type)) {
|
|
68
68
|
throw new MessengerError(`Handler already set for ${type}`);
|
|
69
69
|
}
|
|
70
|
-
debug("Registered", type);
|
|
70
|
+
log.debug("Registered", type);
|
|
71
71
|
handlers.set(type, method);
|
|
72
72
|
}
|
|
73
73
|
browser.runtime.onMessage.addListener(onMessageListener);
|
|
74
74
|
}
|
|
75
|
+
/** Ensure/document that the current function was called via Messenger */
|
|
76
|
+
export function assertMessengerCall(_this
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- TypeScript already does this, it's a documentation-only call
|
|
78
|
+
) { }
|
package/distribution/sender.js
CHANGED
|
@@ -2,7 +2,7 @@ import pRetry from "p-retry";
|
|
|
2
2
|
import { isBackground } from "webext-detect-page";
|
|
3
3
|
import { doesTabExist } from "webext-tools";
|
|
4
4
|
import { deserializeError } from "serialize-error";
|
|
5
|
-
import { isObject, MessengerError, __webextMessenger,
|
|
5
|
+
import { isObject, MessengerError, __webextMessenger, log } from "./shared.js";
|
|
6
6
|
import { handlers } from "./handlers.js";
|
|
7
7
|
const _errorNonExistingTarget = "Could not establish connection. Receiving end does not exist.";
|
|
8
8
|
// https://github.com/mozilla/webextension-polyfill/issues/384
|
|
@@ -12,6 +12,9 @@ export const errorTabDoesntExist = "The tab doesn't exist";
|
|
|
12
12
|
function isMessengerResponse(response) {
|
|
13
13
|
return isObject(response) && response["__webextMessenger"] === true;
|
|
14
14
|
}
|
|
15
|
+
function attemptLog(attemptCount) {
|
|
16
|
+
return attemptCount > 1 ? `(try: ${attemptCount})` : "";
|
|
17
|
+
}
|
|
15
18
|
function makeMessage(type, args, target, options) {
|
|
16
19
|
return {
|
|
17
20
|
__webextMessenger,
|
|
@@ -22,17 +25,17 @@ function makeMessage(type, args, target, options) {
|
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
// Do not turn this into an `async` function; Notifications must turn `void`
|
|
25
|
-
function manageConnection(type,
|
|
26
|
-
if (!
|
|
27
|
-
return manageMessage(type, target, sendMessage);
|
|
28
|
+
function manageConnection(type, { seq, isNotification }, target, sendMessage) {
|
|
29
|
+
if (!isNotification) {
|
|
30
|
+
return manageMessage(type, target, seq, sendMessage);
|
|
28
31
|
}
|
|
29
|
-
void sendMessage().catch((error) => {
|
|
30
|
-
debug(type, "notification failed", { error });
|
|
32
|
+
void sendMessage(1).catch((error) => {
|
|
33
|
+
log.debug(type, seq, "notification failed", { error });
|
|
31
34
|
});
|
|
32
35
|
}
|
|
33
|
-
async function manageMessage(type, target, sendMessage) {
|
|
34
|
-
const response = await pRetry(async () => {
|
|
35
|
-
const response = await sendMessage();
|
|
36
|
+
async function manageMessage(type, target, seq, sendMessage) {
|
|
37
|
+
const response = await pRetry(async (attemptCount) => {
|
|
38
|
+
const response = await sendMessage(attemptCount);
|
|
36
39
|
if (isMessengerResponse(response)) {
|
|
37
40
|
return response;
|
|
38
41
|
}
|
|
@@ -74,7 +77,7 @@ async function manageMessage(type, target, sendMessage) {
|
|
|
74
77
|
!(await doesTabExist(target.tabId))) {
|
|
75
78
|
throw new Error(errorTabDoesntExist);
|
|
76
79
|
}
|
|
77
|
-
debug(type, "will retry. Attempt", error.attemptNumber);
|
|
80
|
+
log.debug(type, seq, "will retry. Attempt", error.attemptNumber);
|
|
78
81
|
}
|
|
79
82
|
else {
|
|
80
83
|
throw error;
|
|
@@ -87,41 +90,44 @@ async function manageMessage(type, target, sendMessage) {
|
|
|
87
90
|
throw error;
|
|
88
91
|
});
|
|
89
92
|
if ("error" in response) {
|
|
90
|
-
debug(type, "โ๏ธ replied with error", response.error);
|
|
93
|
+
log.debug(type, seq, "โ๏ธ replied with error", response.error);
|
|
91
94
|
throw deserializeError(response.error);
|
|
92
95
|
}
|
|
93
|
-
debug(type, "โ๏ธ replied successfully", response.value);
|
|
96
|
+
log.debug(type, seq, "โ๏ธ replied successfully", response.value);
|
|
94
97
|
return response.value;
|
|
95
98
|
}
|
|
96
99
|
function messenger(type, options, target, ...args) {
|
|
100
|
+
// Not a UID. Signal / console noise compromise. They repeat every 100 seconds
|
|
101
|
+
options.seq = Date.now() % 100000;
|
|
102
|
+
const { seq } = options;
|
|
97
103
|
// Message goes to extension page
|
|
98
104
|
if ("page" in target) {
|
|
99
105
|
if (target.page === "background" && isBackground()) {
|
|
100
106
|
const handler = handlers.get(type);
|
|
101
107
|
if (handler) {
|
|
102
|
-
warn(type, "is being handled locally");
|
|
108
|
+
log.warn(type, seq, "is being handled locally");
|
|
103
109
|
return handler.apply({ trace: [] }, args);
|
|
104
110
|
}
|
|
105
111
|
throw new MessengerError("No handler registered locally for " + type);
|
|
106
112
|
}
|
|
107
|
-
const sendMessage = async () => {
|
|
108
|
-
debug(type, "โ๏ธ sending message to runtime");
|
|
113
|
+
const sendMessage = async (attemptCount) => {
|
|
114
|
+
log.debug(type, seq, "โ๏ธ sending message to runtime", attemptLog(attemptCount));
|
|
109
115
|
return browser.runtime.sendMessage(makeMessage(type, args, target, options));
|
|
110
116
|
};
|
|
111
117
|
return manageConnection(type, options, target, sendMessage);
|
|
112
118
|
}
|
|
113
119
|
// Contexts without direct Tab access must go through background
|
|
114
120
|
if (!browser.tabs) {
|
|
115
|
-
return manageConnection(type, options, target, async () => {
|
|
116
|
-
debug(type, "โ๏ธ sending message to runtime");
|
|
121
|
+
return manageConnection(type, options, target, async (attemptCount) => {
|
|
122
|
+
log.debug(type, seq, "โ๏ธ sending message to runtime", attemptLog(attemptCount));
|
|
117
123
|
return browser.runtime.sendMessage(makeMessage(type, args, target, options));
|
|
118
124
|
});
|
|
119
125
|
}
|
|
120
126
|
// `frameId` must be specified. If missing, the message is sent to every frame
|
|
121
127
|
const { tabId, frameId = 0 } = target;
|
|
122
128
|
// Message tab directly
|
|
123
|
-
return manageConnection(type, options, target, async () => {
|
|
124
|
-
debug(type, "โ๏ธ sending message to tab", tabId, "frame", frameId);
|
|
129
|
+
return manageConnection(type, options, target, async (attemptCount) => {
|
|
130
|
+
log.debug(type, seq, "โ๏ธ sending message to tab", tabId, "frame", frameId, attemptLog(attemptCount));
|
|
125
131
|
return browser.tabs.sendMessage(tabId, makeMessage(type, args, target, options), {
|
|
126
132
|
frameId,
|
|
127
133
|
});
|
package/distribution/shared.d.ts
CHANGED
|
@@ -10,8 +10,11 @@ export declare function isObject(value: unknown): value is Record<string, unknow
|
|
|
10
10
|
export declare class MessengerError extends Error {
|
|
11
11
|
name: string;
|
|
12
12
|
}
|
|
13
|
-
export declare const
|
|
14
|
-
|
|
13
|
+
export declare const log: {
|
|
14
|
+
debug: (...args: any[]) => void;
|
|
15
|
+
warn: (...args: any[]) => void;
|
|
16
|
+
};
|
|
17
|
+
export declare function toggleLogging(enabled: boolean): void;
|
|
15
18
|
export declare function isErrorObject(error: unknown): error is ErrorObject;
|
|
16
19
|
export declare function delay(milliseconds: number): Promise<void>;
|
|
17
20
|
export declare function once<Callback extends (...arguments_: unknown[]) => unknown>(function_: Callback): Callback;
|
package/distribution/shared.js
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import { errorConstructors } from "serialize-error";
|
|
2
|
-
const logging = (() => {
|
|
3
|
-
try {
|
|
4
|
-
// @ts-expect-error it would break Webpack
|
|
5
|
-
return process.env.WEBEXT_MESSENGER_LOGGING === "true";
|
|
6
|
-
}
|
|
7
|
-
catch {
|
|
8
|
-
return false;
|
|
9
|
-
}
|
|
10
|
-
})();
|
|
11
|
-
function noop() {
|
|
12
|
-
/* */
|
|
13
|
-
}
|
|
14
2
|
export const __webextMessenger = true;
|
|
15
3
|
export function isObject(value) {
|
|
16
4
|
return typeof value === "object" && value !== null;
|
|
17
5
|
}
|
|
6
|
+
function noop() {
|
|
7
|
+
/* */
|
|
8
|
+
}
|
|
18
9
|
export class MessengerError extends Error {
|
|
19
10
|
constructor() {
|
|
20
11
|
super(...arguments);
|
|
@@ -29,8 +20,15 @@ export class MessengerError extends Error {
|
|
|
29
20
|
// @ts-expect-error Wrong `errorConstructors` types
|
|
30
21
|
errorConstructors.set("MessengerError", MessengerError);
|
|
31
22
|
// .bind preserves the call location in the console
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
const debug = console.debug.bind(console, "Messenger:");
|
|
24
|
+
const warn = console.warn.bind(console, "Messenger:");
|
|
25
|
+
export const log = { debug, warn };
|
|
26
|
+
export function toggleLogging(enabled) {
|
|
27
|
+
log.debug = enabled ? debug : noop;
|
|
28
|
+
log.warn = enabled ? warn : noop;
|
|
29
|
+
}
|
|
30
|
+
// Default to "no logs"
|
|
31
|
+
toggleLogging(false);
|
|
34
32
|
export function isErrorObject(error) {
|
|
35
33
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a type guard function and it uses ?.
|
|
36
34
|
return typeof error?.message === "string";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isBackground, isContentScript, isExtensionContext, } from "webext-detect-page";
|
|
2
2
|
import { messenger } from "./sender.js";
|
|
3
3
|
import { registerMethods } from "./receiver.js";
|
|
4
|
-
import {
|
|
4
|
+
import { log, MessengerError, once } from "./shared.js";
|
|
5
5
|
/**
|
|
6
6
|
* @file This file exists because `runtime.sendMessage` acts as a broadcast to
|
|
7
7
|
* all open extension pages, so the receiver needs a way to figure out if the
|
|
@@ -84,7 +84,7 @@ export function getActionForMessage(from, message) {
|
|
|
84
84
|
// Every `target` key must match `thisTarget`
|
|
85
85
|
const isThisTarget = compareTargets(to, thisTarget);
|
|
86
86
|
if (!isThisTarget) {
|
|
87
|
-
debug(message.type, "๐คซ ignored due to target mismatch", {
|
|
87
|
+
log.debug(message.type, "๐คซ ignored due to target mismatch", {
|
|
88
88
|
requestedTarget: to,
|
|
89
89
|
thisTarget,
|
|
90
90
|
tabDataStatus,
|
package/distribution/types.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type MessengerResponse = RawMessengerResponse & {
|
|
|
28
28
|
/** Guarantees that the message was handled by this library */
|
|
29
29
|
__webextMessenger: true;
|
|
30
30
|
};
|
|
31
|
-
type Arguments =
|
|
31
|
+
type Arguments = unknown[];
|
|
32
32
|
export type Method = (this: MessengerMeta, ...args: Arguments) => Promise<unknown>;
|
|
33
33
|
export interface Options {
|
|
34
34
|
/**
|
|
@@ -37,6 +37,8 @@ export interface Options {
|
|
|
37
37
|
*/
|
|
38
38
|
isNotification?: boolean;
|
|
39
39
|
trace?: Sender[];
|
|
40
|
+
/** Automatically generated internally */
|
|
41
|
+
seq?: number;
|
|
40
42
|
}
|
|
41
43
|
export type Message<LocalArguments extends Arguments = Arguments> = {
|
|
42
44
|
type: keyof MessengerMethods;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webext-messenger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Browser Extension component messaging framework",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": "pixiebrix/webext-messenger",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"main": "distribution/index.js",
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
|
-
"demo:watch": "
|
|
13
|
+
"demo:watch": "parcel watch --no-cache --no-hmr",
|
|
14
14
|
"demo:build": "parcel build --no-cache",
|
|
15
15
|
"prepack": "tsc --sourceMap false",
|
|
16
16
|
"test": "eslint . && tsc --noEmit",
|
|
@@ -19,30 +19,30 @@
|
|
|
19
19
|
"watch": "tsc --watch"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"p-retry": "^
|
|
23
|
-
"serialize-error": "^11.0.
|
|
24
|
-
"type-fest": "^3.
|
|
25
|
-
"webext-detect-page": "^4.
|
|
26
|
-
"webext-tools": "^1.1.
|
|
22
|
+
"p-retry": "^6.0.0",
|
|
23
|
+
"serialize-error": "^11.0.2",
|
|
24
|
+
"type-fest": "^4.3.1",
|
|
25
|
+
"webext-detect-page": "^4.1.1",
|
|
26
|
+
"webext-tools": "^1.1.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@parcel/config-webextension": "^2.
|
|
30
|
-
"@sindresorhus/tsconfig": "^
|
|
31
|
-
"@types/chrome": "^0.0.
|
|
32
|
-
"@types/tape": "^
|
|
33
|
-
"@types/webextension-polyfill": "^0.
|
|
29
|
+
"@parcel/config-webextension": "^2.6.2",
|
|
30
|
+
"@sindresorhus/tsconfig": "^4.0.0",
|
|
31
|
+
"@types/chrome": "^0.0.245",
|
|
32
|
+
"@types/tape": "^5.6.1",
|
|
33
|
+
"@types/webextension-polyfill": "^0.10.2",
|
|
34
34
|
"buffer": "^6.0.3",
|
|
35
|
-
"eslint": "^8.
|
|
36
|
-
"eslint-config-pixiebrix": "^0.
|
|
35
|
+
"eslint": "^8.29.0",
|
|
36
|
+
"eslint-config-pixiebrix": "^0.27.2",
|
|
37
37
|
"events": "^3.3.0",
|
|
38
38
|
"npm-run-all": "^4.1.5",
|
|
39
|
-
"parcel": "^2.6.
|
|
39
|
+
"parcel": "^2.6.2",
|
|
40
40
|
"path-browserify": "^1.0.1",
|
|
41
41
|
"process": "^0.11.10",
|
|
42
42
|
"stream-browserify": "^3.0.0",
|
|
43
|
-
"tape": "^5.
|
|
44
|
-
"typescript": "^
|
|
45
|
-
"webext-content-scripts": "^
|
|
43
|
+
"tape": "^5.6.6",
|
|
44
|
+
"typescript": "^5.2.2",
|
|
45
|
+
"webext-content-scripts": "^2.5.5",
|
|
46
46
|
"webextension-polyfill": "^0.10.0"
|
|
47
47
|
},
|
|
48
48
|
"alias": {
|
package/readme.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[badge-gzip]: https://img.shields.io/bundlephobia/minzip/webext-messenger.svg?label=gzipped
|
|
4
4
|
[link-bundlephobia]: https://bundlephobia.com/result?p=webext-messenger
|
|
5
5
|
|
|
6
|
-
>
|
|
6
|
+
> Browser Extension component messaging framework
|
|
7
7
|
|
|
8
8
|
## Install
|
|
9
9
|
|
|
@@ -17,4 +17,9 @@ import messenger from "webext-messenger";
|
|
|
17
17
|
|
|
18
18
|
## Context
|
|
19
19
|
|
|
20
|
-
- [Initial
|
|
20
|
+
- [Initial considertions for this library](https://github.com/pixiebrix/webext-messenger/issues/1)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## npm publishing
|
|
24
|
+
|
|
25
|
+
Collaborators can publish a new version of what's on main [via "workflow_dispatch"](https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/) under [Actions ยป Publish](https://github.com/pixiebrix/webext-messenger/actions/workflows/npm-publish.yml)
|