webext-messenger 0.6.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- package/distribution/index.d.ts +5 -4
- package/distribution/index.js +44 -33
- package/package.json +2 -1
package/distribution/index.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
/// <reference types="firefox-webext-browser" />
|
2
|
+
import { Asyncify } from "type-fest";
|
2
3
|
declare global {
|
3
4
|
interface MessengerMethods {
|
4
5
|
_: Method;
|
@@ -9,19 +10,19 @@ export declare type MessengerMeta = browser.runtime.MessageSender;
|
|
9
10
|
declare type Arguments = any[];
|
10
11
|
declare type Method = (this: MessengerMeta, ...args: Arguments) => Promise<unknown>;
|
11
12
|
export interface Target {
|
12
|
-
|
13
|
-
|
13
|
+
tabId: number;
|
14
|
+
frameId?: number;
|
14
15
|
}
|
15
16
|
declare type WithTarget<TMethod> = TMethod extends (...args: infer PreviousArguments) => infer TReturnValue ? (target: Target, ...args: PreviousArguments) => TReturnValue : never;
|
16
17
|
/**
|
17
18
|
* Replicates the original method, including its types.
|
18
19
|
* To be called in the sender’s end.
|
19
20
|
*/
|
20
|
-
export declare function getContentScriptMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], PublicMethod extends WithTarget<ActuallyOmitThisParameter<TMethod
|
21
|
+
export declare function getContentScriptMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], PublicMethod extends WithTarget<Asyncify<ActuallyOmitThisParameter<TMethod>>>>(type: TType): PublicMethod;
|
21
22
|
/**
|
22
23
|
* Replicates the original method, including its types.
|
23
24
|
* To be called in the sender’s end.
|
24
25
|
*/
|
25
|
-
export declare function getMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], PublicMethod extends ActuallyOmitThisParameter<TMethod
|
26
|
+
export declare function getMethod<TType extends keyof MessengerMethods, TMethod extends MessengerMethods[TType], PublicMethod extends Asyncify<ActuallyOmitThisParameter<TMethod>>>(type: TType): PublicMethod;
|
26
27
|
export declare function registerMethods(methods: Partial<MessengerMethods>): void;
|
27
28
|
export {};
|
package/distribution/index.js
CHANGED
@@ -1,29 +1,49 @@
|
|
1
1
|
import { deserializeError, serializeError } from "serialize-error";
|
2
|
-
const
|
2
|
+
const __webext_messenger__ = true;
|
3
3
|
function isObject(value) {
|
4
4
|
return typeof value === "object" && value !== null;
|
5
5
|
}
|
6
|
-
function isMessengerMessage(
|
7
|
-
return (isObject(
|
8
|
-
typeof
|
9
|
-
|
10
|
-
Array.isArray(
|
6
|
+
function isMessengerMessage(message) {
|
7
|
+
return (isObject(message) &&
|
8
|
+
typeof message["type"] === "string" &&
|
9
|
+
message["__webext_messenger__"] === true &&
|
10
|
+
Array.isArray(message["args"]));
|
11
|
+
}
|
12
|
+
function isMessengerResponse(response) {
|
13
|
+
return isObject(response) && response["__webext_messenger__"] === true;
|
11
14
|
}
|
12
15
|
const handlers = new Map();
|
16
|
+
async function handleMessage(message, sender) {
|
17
|
+
const handler = handlers.get(message.type);
|
18
|
+
if (!handler) {
|
19
|
+
throw new Error("No handler registered for " + message.type);
|
20
|
+
}
|
21
|
+
console.debug(`Messenger:`, message.type, message.args, "from", { sender });
|
22
|
+
// The handler could actually be a synchronous function
|
23
|
+
const response = await Promise.resolve(handler.call(sender, ...message.args)).then((value) => ({ value }), (error) => ({
|
24
|
+
// Errors must be serialized because the stacktraces are currently lost on Chrome and
|
25
|
+
// https://github.com/mozilla/webextension-polyfill/issues/210
|
26
|
+
error: serializeError(error),
|
27
|
+
}));
|
28
|
+
console.debug(`Messenger:`, message.type, "responds", response);
|
29
|
+
return { ...response, __webext_messenger__ };
|
30
|
+
}
|
31
|
+
async function handleResponse(response) {
|
32
|
+
if (!isMessengerResponse(response)) {
|
33
|
+
// If the response is `undefined`, `registerMethod` was never called
|
34
|
+
throw new Error("No handlers registered in receiving end");
|
35
|
+
}
|
36
|
+
if ("error" in response) {
|
37
|
+
throw deserializeError(response.error);
|
38
|
+
}
|
39
|
+
return response.value;
|
40
|
+
}
|
13
41
|
// MUST NOT be `async` or Promise-returning-only
|
14
42
|
function onMessageListener(message, sender) {
|
15
|
-
if (
|
16
|
-
return;
|
17
|
-
}
|
18
|
-
const handler = handlers.get(message.type);
|
19
|
-
if (handler) {
|
20
|
-
return handler.call(sender, ...message.args).catch((error) => ({
|
21
|
-
// Errors must be serialized because the stacktraces are currently lost on Chrome and
|
22
|
-
// https://github.com/mozilla/webextension-polyfill/issues/210
|
23
|
-
[errorKey]: serializeError(error),
|
24
|
-
}));
|
43
|
+
if (isMessengerMessage(message)) {
|
44
|
+
return handleMessage(message, sender);
|
25
45
|
}
|
26
|
-
|
46
|
+
// TODO: Add test for this eventuality: ignore unrelated messages
|
27
47
|
}
|
28
48
|
/**
|
29
49
|
* Replicates the original method, including its types.
|
@@ -32,21 +52,16 @@ function onMessageListener(message, sender) {
|
|
32
52
|
export function getContentScriptMethod(type) {
|
33
53
|
const publicMethod = async (target, ...args) => {
|
34
54
|
var _a;
|
35
|
-
|
36
|
-
// i.e. if registerMethods hasn't been called
|
37
|
-
const response = await browser.tabs.sendMessage(target.tab, {
|
55
|
+
const response = await browser.tabs.sendMessage(target.tabId, {
|
38
56
|
// Guarantees that a message is meant to be handled by this library
|
39
|
-
__webext_messenger__
|
57
|
+
__webext_messenger__,
|
40
58
|
type,
|
41
59
|
args,
|
42
60
|
}, {
|
43
61
|
// Must be specified. If missing, the message would be sent to every frame
|
44
|
-
frameId: (_a = target.
|
62
|
+
frameId: (_a = target.frameId) !== null && _a !== void 0 ? _a : 0,
|
45
63
|
});
|
46
|
-
|
47
|
-
throw deserializeError(response[errorKey]);
|
48
|
-
}
|
49
|
-
return response;
|
64
|
+
return handleResponse(response);
|
50
65
|
};
|
51
66
|
return publicMethod;
|
52
67
|
}
|
@@ -56,18 +71,13 @@ export function getContentScriptMethod(type) {
|
|
56
71
|
*/
|
57
72
|
export function getMethod(type) {
|
58
73
|
const publicMethod = async (...args) => {
|
59
|
-
// TODO: This will throw if the receiving end doesn't exist,
|
60
|
-
// i.e. if registerMethods hasn't been called
|
61
74
|
const response = await browser.runtime.sendMessage({
|
62
75
|
// Guarantees that a message is meant to be handled by this library
|
63
|
-
__webext_messenger__
|
76
|
+
__webext_messenger__,
|
64
77
|
type,
|
65
78
|
args,
|
66
79
|
});
|
67
|
-
|
68
|
-
throw deserializeError(response[errorKey]);
|
69
|
-
}
|
70
|
-
return response;
|
80
|
+
return handleResponse(response);
|
71
81
|
};
|
72
82
|
return publicMethod;
|
73
83
|
}
|
@@ -76,6 +86,7 @@ export function registerMethods(methods) {
|
|
76
86
|
if (handlers.has(type)) {
|
77
87
|
throw new Error(`Handler already set for ${type}`);
|
78
88
|
}
|
89
|
+
console.debug(`Messenger: Registered`, type);
|
79
90
|
handlers.set(type, method);
|
80
91
|
}
|
81
92
|
browser.runtime.onMessage.addListener(onMessageListener);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "webext-messenger",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.7.1",
|
4
4
|
"description": "Browser Extension component messaging framework",
|
5
5
|
"keywords": [],
|
6
6
|
"repository": "pixiebrix/extension-messaging",
|
@@ -69,6 +69,7 @@
|
|
69
69
|
},
|
70
70
|
"dependencies": {
|
71
71
|
"serialize-error": "^8.1.0",
|
72
|
+
"type-fest": "^2.3.4",
|
72
73
|
"webext-detect-page": "^3.0.2",
|
73
74
|
"webextension-polyfill": "^0.8.0"
|
74
75
|
},
|