webext-messenger 0.7.1 → 0.9.2
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 +22 -6
- package/distribution/index.js +45 -32
- package/package.json +25 -12
package/distribution/index.d.ts
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
/// <reference types="firefox-webext-browser" />
|
2
|
-
import { Asyncify } from "type-fest";
|
2
|
+
import { Asyncify, SetReturnType, ValueOf } from "type-fest";
|
3
3
|
declare global {
|
4
4
|
interface MessengerMethods {
|
5
5
|
_: Method;
|
6
6
|
}
|
7
7
|
}
|
8
|
+
declare type WithTarget<TMethod> = TMethod extends (...args: infer PreviousArguments) => infer TReturnValue ? (target: Target, ...args: PreviousArguments) => TReturnValue : never;
|
8
9
|
declare type ActuallyOmitThisParameter<T> = T extends (...args: infer A) => infer R ? (...args: A) => R : T;
|
10
|
+
/** Removes the `this` type and ensure it's always Promised */
|
11
|
+
declare type PublicMethod<TMethod extends ValueOf<MessengerMethods>> = Asyncify<ActuallyOmitThisParameter<TMethod>>;
|
12
|
+
declare type PublicMethodWithTarget<TMethod extends ValueOf<MessengerMethods>> = WithTarget<PublicMethod<TMethod>>;
|
9
13
|
export declare type MessengerMeta = browser.runtime.MessageSender;
|
10
14
|
declare type Arguments = any[];
|
11
15
|
declare type Method = (this: MessengerMeta, ...args: Arguments) => Promise<unknown>;
|
@@ -13,16 +17,28 @@ export interface Target {
|
|
13
17
|
tabId: number;
|
14
18
|
frameId?: number;
|
15
19
|
}
|
16
|
-
|
20
|
+
interface Options {
|
21
|
+
/**
|
22
|
+
* "Notifications" won't await the response, return values, attempt retries, nor throw errors
|
23
|
+
* @default false
|
24
|
+
*/
|
25
|
+
isNotification?: boolean;
|
26
|
+
}
|
17
27
|
/**
|
18
28
|
* Replicates the original method, including its types.
|
19
29
|
* To be called in the sender’s end.
|
20
30
|
*/
|
21
|
-
|
31
|
+
declare function getContentScriptMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], TPublicMethod extends PublicMethodWithTarget<TMethod>>(type: TType, options: {
|
32
|
+
isNotification: true;
|
33
|
+
}): SetReturnType<TPublicMethod, void>;
|
34
|
+
declare function getContentScriptMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], TPublicMethod extends PublicMethodWithTarget<TMethod>>(type: TType, options?: Options): TPublicMethod;
|
22
35
|
/**
|
23
36
|
* Replicates the original method, including its types.
|
24
37
|
* To be called in the sender’s end.
|
25
38
|
*/
|
26
|
-
|
27
|
-
|
28
|
-
|
39
|
+
declare function getMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], TPublicMethod extends PublicMethod<TMethod>>(type: TType, options: {
|
40
|
+
isNotification: true;
|
41
|
+
}): SetReturnType<TPublicMethod, void>;
|
42
|
+
declare function getMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], TPublicMethod extends PublicMethod<TMethod>>(type: TType, options?: Options): TPublicMethod;
|
43
|
+
declare function registerMethods(methods: Partial<MessengerMethods>): void;
|
44
|
+
export { getMethod, getContentScriptMethod, registerMethods };
|
package/distribution/index.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import pRetry from "p-retry";
|
1
2
|
import { deserializeError, serializeError } from "serialize-error";
|
2
3
|
const __webext_messenger__ = true;
|
3
4
|
function isObject(value) {
|
@@ -28,7 +29,28 @@ async function handleMessage(message, sender) {
|
|
28
29
|
console.debug(`Messenger:`, message.type, "responds", response);
|
29
30
|
return { ...response, __webext_messenger__ };
|
30
31
|
}
|
31
|
-
async function
|
32
|
+
// Do not turn this into an `async` function; Notifications must turn `void`
|
33
|
+
function manageConnection(type, options, sendMessage) {
|
34
|
+
if (!options.isNotification) {
|
35
|
+
return manageMessage(type, sendMessage);
|
36
|
+
}
|
37
|
+
void sendMessage().catch((error) => {
|
38
|
+
console.debug("Messenger:", type, "notification failed", { error });
|
39
|
+
});
|
40
|
+
}
|
41
|
+
async function manageMessage(type, sendMessage) {
|
42
|
+
const response = await pRetry(sendMessage, {
|
43
|
+
minTimeout: 100,
|
44
|
+
factor: 1.3,
|
45
|
+
maxRetryTime: 4000,
|
46
|
+
onFailedAttempt(error) {
|
47
|
+
if ((error === null || error === void 0 ? void 0 : error.message) !==
|
48
|
+
"Could not establish connection. Receiving end does not exist.") {
|
49
|
+
throw error;
|
50
|
+
}
|
51
|
+
console.debug("Messenger:", type, "will retry");
|
52
|
+
},
|
53
|
+
});
|
32
54
|
if (!isMessengerResponse(response)) {
|
33
55
|
// If the response is `undefined`, `registerMethod` was never called
|
34
56
|
throw new Error("No handlers registered in receiving end");
|
@@ -45,43 +67,33 @@ function onMessageListener(message, sender) {
|
|
45
67
|
}
|
46
68
|
// TODO: Add test for this eventuality: ignore unrelated messages
|
47
69
|
}
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
args,
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
return handleResponse(response);
|
70
|
+
function makeMessage(type, args) {
|
71
|
+
return {
|
72
|
+
__webext_messenger__,
|
73
|
+
type,
|
74
|
+
args,
|
75
|
+
};
|
76
|
+
}
|
77
|
+
function getContentScriptMethod(type, options = {}) {
|
78
|
+
const publicMethod = (target, ...args) => {
|
79
|
+
const sendMessage = async () => {
|
80
|
+
var _a;
|
81
|
+
return browser.tabs.sendMessage(target.tabId, makeMessage(type, args),
|
82
|
+
// `frameId` must be specified. If missing, the message would be sent to every frame
|
83
|
+
{ frameId: (_a = target.frameId) !== null && _a !== void 0 ? _a : 0 });
|
84
|
+
};
|
85
|
+
return manageConnection(type, options, sendMessage);
|
65
86
|
};
|
66
87
|
return publicMethod;
|
67
88
|
}
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
export function getMethod(type) {
|
73
|
-
const publicMethod = async (...args) => {
|
74
|
-
const response = await browser.runtime.sendMessage({
|
75
|
-
// Guarantees that a message is meant to be handled by this library
|
76
|
-
__webext_messenger__,
|
77
|
-
type,
|
78
|
-
args,
|
79
|
-
});
|
80
|
-
return handleResponse(response);
|
89
|
+
function getMethod(type, options = {}) {
|
90
|
+
const publicMethod = (...args) => {
|
91
|
+
const sendMessage = async () => browser.runtime.sendMessage(makeMessage(type, args));
|
92
|
+
return manageConnection(type, options, sendMessage);
|
81
93
|
};
|
82
94
|
return publicMethod;
|
83
95
|
}
|
84
|
-
|
96
|
+
function registerMethods(methods) {
|
85
97
|
for (const [type, method] of Object.entries(methods)) {
|
86
98
|
if (handlers.has(type)) {
|
87
99
|
throw new Error(`Handler already set for ${type}`);
|
@@ -91,3 +103,4 @@ export function registerMethods(methods) {
|
|
91
103
|
}
|
92
104
|
browser.runtime.onMessage.addListener(onMessageListener);
|
93
105
|
}
|
106
|
+
export { getMethod, getContentScriptMethod, registerMethods };
|
package/package.json
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "webext-messenger",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.9.2",
|
4
4
|
"description": "Browser Extension component messaging framework",
|
5
5
|
"keywords": [],
|
6
6
|
"repository": "pixiebrix/extension-messaging",
|
7
7
|
"license": "MIT",
|
8
8
|
"author": "Federico Brigante for PixieBrix <federico@pixiebrix.com> (https://www.pixiebrix.com)",
|
9
9
|
"type": "module",
|
10
|
-
"
|
10
|
+
"exports": "./distribution/index.js",
|
11
|
+
"types": "distribution/index.d.ts",
|
11
12
|
"files": [
|
12
13
|
"distribution/index.js",
|
13
14
|
"distribution/index.d.ts"
|
@@ -42,18 +43,19 @@
|
|
42
43
|
"plugin:unicorn/recommended"
|
43
44
|
],
|
44
45
|
"rules": {
|
45
|
-
"@typescript-eslint/no-require-imports": "off",
|
46
46
|
"@typescript-eslint/no-unsafe-member-access": "off",
|
47
|
-
"import/extensions": "off",
|
48
|
-
"import/no-unassigned-import": "off",
|
49
|
-
"node/file-extension-in-import": "off",
|
50
47
|
"unicorn/filename-case": [
|
51
48
|
"error",
|
52
49
|
{
|
53
50
|
"case": "camelCase"
|
54
51
|
}
|
55
52
|
],
|
56
|
-
"unicorn/
|
53
|
+
"unicorn/no-useless-undefined": [
|
54
|
+
"error",
|
55
|
+
{
|
56
|
+
"checkArguments": false
|
57
|
+
}
|
58
|
+
],
|
57
59
|
"unicorn/prevent-abbreviations": [
|
58
60
|
"error",
|
59
61
|
{
|
@@ -63,11 +65,22 @@
|
|
63
65
|
}
|
64
66
|
]
|
65
67
|
},
|
68
|
+
"overrides": [
|
69
|
+
{
|
70
|
+
"files": [
|
71
|
+
"*.test.ts"
|
72
|
+
],
|
73
|
+
"rules": {
|
74
|
+
"@typescript-eslint/no-non-null-assertion": "off"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
],
|
66
78
|
"globals": {
|
67
79
|
"chrome": true
|
68
80
|
}
|
69
81
|
},
|
70
82
|
"dependencies": {
|
83
|
+
"p-retry": "^4.6.1",
|
71
84
|
"serialize-error": "^8.1.0",
|
72
85
|
"type-fest": "^2.3.4",
|
73
86
|
"webext-detect-page": "^3.0.2",
|
@@ -76,20 +89,20 @@
|
|
76
89
|
"devDependencies": {
|
77
90
|
"@parcel/config-webextension": "^2.0.0-rc.0",
|
78
91
|
"@sindresorhus/tsconfig": "^2.0.0",
|
79
|
-
"@types/chrome": "^0.0.
|
92
|
+
"@types/chrome": "^0.0.158",
|
80
93
|
"@types/firefox-webext-browser": "^82.0.1",
|
81
|
-
"@typescript-eslint/eslint-plugin": "^4.
|
82
|
-
"@typescript-eslint/parser": "^4.
|
94
|
+
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
95
|
+
"@typescript-eslint/parser": "^4.31.2",
|
83
96
|
"eslint": "^7.32.0",
|
84
97
|
"eslint-config-prettier": "^8.3.0",
|
85
98
|
"eslint-config-xo": "^0.38.0",
|
86
99
|
"eslint-config-xo-typescript": "^0.44.0",
|
87
100
|
"eslint-plugin-import": "^2.24.2",
|
88
|
-
"eslint-plugin-unicorn": "^
|
101
|
+
"eslint-plugin-unicorn": "^36.0.0",
|
89
102
|
"fresh-tape": "^5.3.1",
|
90
103
|
"npm-run-all": "^4.1.5",
|
91
104
|
"parcel": "^2.0.0-rc.0",
|
92
|
-
"typescript": "^4.4.
|
105
|
+
"typescript": "^4.4.3",
|
93
106
|
"xo": "^0.44.0"
|
94
107
|
},
|
95
108
|
"targets": {
|