webext-messenger 0.6.0 → 0.7.1
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 +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
|
},
|