webext-messenger 0.33.0-1 → 0.33.0-3
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/receiver.d.ts +1 -1
- package/distribution/receiver.js +14 -14
- package/distribution/sender.d.ts +5 -5
- package/distribution/sender.js +12 -3
- package/distribution/shared.d.ts +3 -0
- package/distribution/shared.js +3 -0
- package/distribution/targetLogic.d.ts +3 -3
- package/distribution/thisTarget.d.ts +2 -2
- package/distribution/types.d.ts +5 -4
- package/package.json +1 -1
@@ -2,6 +2,6 @@ import { type Message, type ExternalMessage, type MessengerMeta } from "./types.
|
|
2
2
|
export declare function isMessengerMessage(message: unknown): message is Message;
|
3
3
|
export declare function isExternalMessengerMessage(message: unknown): message is ExternalMessage;
|
4
4
|
export declare function registerMethods(methods: Partial<MessengerMethods>): void;
|
5
|
-
export declare function
|
5
|
+
export declare function exposeMethodsToExternalMessaging(...types: Array<keyof MessengerMethods>): void;
|
6
6
|
/** Ensure/document that the current function was called via Messenger */
|
7
7
|
export declare function assertMessengerCall(_this: MessengerMeta): asserts _this is MessengerMeta;
|
package/distribution/receiver.js
CHANGED
@@ -14,13 +14,10 @@ export function isMessengerMessage(message) {
|
|
14
14
|
Array.isArray(message["args"]));
|
15
15
|
}
|
16
16
|
export function isExternalMessengerMessage(message) {
|
17
|
-
return (
|
18
|
-
|
19
|
-
message
|
20
|
-
|
21
|
-
isObject(message["target"]) &&
|
22
|
-
Object.keys(message["target"]).length === 1 && // Ensure it's *only* `extensionId`
|
23
|
-
typeof message["target"]["extensionId"] === "string");
|
17
|
+
return (isMessengerMessage(message) &&
|
18
|
+
isObject(message.target) &&
|
19
|
+
Object.keys(message.target).length === 1 && // Ensure it's *only* `extensionId`
|
20
|
+
typeof message.target.extensionId === "string");
|
24
21
|
}
|
25
22
|
/**
|
26
23
|
* Decides what to do with a message and sends a response (value or error) back to the sender.
|
@@ -69,13 +66,16 @@ function onMessageListener(message, sender, sendResponse) {
|
|
69
66
|
sendResponse({ __webextMessenger, error: serializeError(error) });
|
70
67
|
}
|
71
68
|
})();
|
72
|
-
// This indicates that the message is being handled and a response will be sent asynchronously
|
73
|
-
//
|
69
|
+
// This indicates that the message is being handled and a response will be sent asynchronously.
|
70
|
+
// It can be improved if this is ever implemented https://issues.chromium.org/issues/40753031
|
74
71
|
return true;
|
75
72
|
}
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
/**
|
74
|
+
* Early validation to ensure that the message matches the specific allowed target
|
75
|
+
* before letting it flow into the rest of messenger. An malicious message might
|
76
|
+
* otherwise pass internal checks and be forwarded to the wrong context.
|
77
|
+
* @warn Do not remove. Keep as a security measure.
|
78
|
+
*/
|
79
79
|
function onMessageExternalListener(message, sender, sendResponse) {
|
80
80
|
if (isExternalMessengerMessage(message) &&
|
81
81
|
message.target.extensionId === chrome.runtime.id) {
|
@@ -95,7 +95,7 @@ async function prepareResponse(message, action, meta) {
|
|
95
95
|
const localHandler = handlers.get(type);
|
96
96
|
if (localHandler) {
|
97
97
|
if ("extensionId" in target && !externalMethods.has(type)) {
|
98
|
-
throw new MessengerError(
|
98
|
+
throw new MessengerError(`The ${type} handler is registered in ${getContextName()} for internal use only`);
|
99
99
|
}
|
100
100
|
return localHandler.apply(meta, args);
|
101
101
|
}
|
@@ -120,7 +120,7 @@ export function registerMethods(methods) {
|
|
120
120
|
chrome.runtime.onMessageExternal.addListener(onMessageExternalListener);
|
121
121
|
}
|
122
122
|
}
|
123
|
-
export function
|
123
|
+
export function exposeMethodsToExternalMessaging(...types) {
|
124
124
|
for (const type of types) {
|
125
125
|
externalMethods.add(type);
|
126
126
|
}
|
package/distribution/sender.d.ts
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
import { type PublicMethod, type PublicMethodWithTarget, type Options, type
|
1
|
+
import { type PublicMethod, type PublicMethodWithTarget, type Options, type AnyTarget, type PageTarget } from "./types.js";
|
2
2
|
import { type Promisable, type SetReturnType } from "type-fest";
|
3
3
|
export declare const errorTargetClosedEarly = "The target was closed before receiving a response";
|
4
4
|
export declare const errorTabDoesntExist = "The tab doesn't exist";
|
5
5
|
export declare const errorTabWasDiscarded = "The tab was discarded";
|
6
6
|
declare function messenger<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type]>(type: Type, options: {
|
7
7
|
isNotification: true;
|
8
|
-
}, target:
|
9
|
-
declare function messenger<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], ReturnValue extends Promise<ReturnType<Method>>>(type: Type, options: Options, target:
|
10
|
-
declare function getMethod<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodType extends PublicMethod<Method>>(type: Type, target: Promisable<
|
8
|
+
}, target: AnyTarget, ...args: Parameters<Method>): void;
|
9
|
+
declare function messenger<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], ReturnValue extends Promise<ReturnType<Method>>>(type: Type, options: Options, target: AnyTarget, ...args: Parameters<Method>): ReturnValue;
|
10
|
+
declare function getMethod<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodType extends PublicMethod<Method>>(type: Type, target: Promisable<AnyTarget>): PublicMethodType;
|
11
11
|
declare function getMethod<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodWithDynamicTarget extends PublicMethodWithTarget<Method>>(type: Type): PublicMethodWithDynamicTarget;
|
12
|
-
declare function getNotifier<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodType extends SetReturnType<PublicMethod<Method>, void>>(type: Type, target: Promisable<
|
12
|
+
declare function getNotifier<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodType extends SetReturnType<PublicMethod<Method>, void>>(type: Type, target: Promisable<AnyTarget>): PublicMethodType;
|
13
13
|
declare function getNotifier<Type extends keyof MessengerMethods, Method extends MessengerMethods[Type], PublicMethodWithDynamicTarget extends SetReturnType<PublicMethodWithTarget<Method>, void>>(type: Type): PublicMethodWithDynamicTarget;
|
14
14
|
export { messenger, getMethod, getNotifier };
|
15
15
|
export declare const backgroundTarget: PageTarget;
|
package/distribution/sender.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import pRetry from "p-retry";
|
2
|
-
import { isBackground } from "webext-detect";
|
2
|
+
import { isBackground, isExtensionContext } from "webext-detect";
|
3
3
|
import { deserializeError } from "serialize-error";
|
4
|
-
import { isObject, MessengerError, __webextMessenger } from "./shared.js";
|
4
|
+
import { isObject, MessengerError, ExtensionNotFoundError, __webextMessenger, } from "./shared.js";
|
5
5
|
import { log } from "./logging.js";
|
6
6
|
import { handlers } from "./handlers.js";
|
7
7
|
import { events } from "./events.js";
|
@@ -10,6 +10,7 @@ const _errorTargetClosedEarly = "A listener indicated an asynchronous response b
|
|
10
10
|
export const errorTargetClosedEarly = "The target was closed before receiving a response";
|
11
11
|
export const errorTabDoesntExist = "The tab doesn't exist";
|
12
12
|
export const errorTabWasDiscarded = "The tab was discarded";
|
13
|
+
const errorExtensionNotFound = "Extension $ID is not installed or externally connectable";
|
13
14
|
function isMessengerResponse(response) {
|
14
15
|
return isObject(response) && response["__webextMessenger"] === true;
|
15
16
|
}
|
@@ -78,7 +79,12 @@ async function manageMessage(type, target, seq, retry, sendMessage) {
|
|
78
79
|
attemptCount: error.attemptNumber,
|
79
80
|
},
|
80
81
|
}));
|
81
|
-
if (
|
82
|
+
if ("extensionId" in target &&
|
83
|
+
error.message === _errorNonExistingTarget) {
|
84
|
+
// The extension is not available and it will not be. Do not retry.
|
85
|
+
throw new ExtensionNotFoundError(errorExtensionNotFound.replace("$ID", target.extensionId));
|
86
|
+
}
|
87
|
+
if (isExtensionContext() && wasContextInvalidated()) {
|
82
88
|
// The error matches the native context invalidated error
|
83
89
|
// *.sendMessage() might fail with a message-specific error that is less useful,
|
84
90
|
// like "Sender closed without responding"
|
@@ -142,6 +148,9 @@ function messenger(type, options, target, ...args) {
|
|
142
148
|
options.seq = globalSeq++;
|
143
149
|
const { seq } = options;
|
144
150
|
if ("extensionId" in target) {
|
151
|
+
if (!globalThis.chrome?.runtime?.sendMessage) {
|
152
|
+
throw new ExtensionNotFoundError(errorExtensionNotFound.replace("$ID", target.extensionId));
|
153
|
+
}
|
145
154
|
const sendMessage = async (attemptCount) => {
|
146
155
|
log.debug(type, seq, "↗️ sending message to extension", attemptLog(attemptCount));
|
147
156
|
return chrome.runtime.sendMessage(target.extensionId, makeMessage(type, args, target, options));
|
package/distribution/shared.d.ts
CHANGED
@@ -10,6 +10,9 @@ 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 class ExtensionNotFoundError extends MessengerError {
|
14
|
+
name: string;
|
15
|
+
}
|
13
16
|
export declare function isErrorObject(error: unknown): error is ErrorObject;
|
14
17
|
export declare function delay(milliseconds: number): Promise<void>;
|
15
18
|
export declare function once<Callback extends (...arguments_: unknown[]) => unknown>(function_: Callback): Callback;
|
package/distribution/shared.js
CHANGED
@@ -6,6 +6,9 @@ export function isObject(value) {
|
|
6
6
|
export class MessengerError extends Error {
|
7
7
|
name = "MessengerError";
|
8
8
|
}
|
9
|
+
export class ExtensionNotFoundError extends MessengerError {
|
10
|
+
name = "ExtensionNotFoundError";
|
11
|
+
}
|
9
12
|
addKnownErrorConstructor(MessengerError);
|
10
13
|
export function isErrorObject(error) {
|
11
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a type guard function and it uses ?.
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import { type
|
2
|
-
export declare function compareTargets(to:
|
3
|
-
export declare function getActionForMessage(from: Sender, target:
|
1
|
+
import { type LooseTarget, type Sender } from "./types.js";
|
2
|
+
export declare function compareTargets(to: LooseTarget, thisTarget: LooseTarget): boolean;
|
3
|
+
export declare function getActionForMessage(from: Sender, target: LooseTarget, thisTarget: LooseTarget): "respond" | "forward" | "ignore";
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { type
|
1
|
+
import { type LooseTarget, type KnownTarget, type TopLevelFrame, type MessengerMeta, type FrameTarget } from "./types.js";
|
2
2
|
/**
|
3
3
|
* @file This file exists because `runtime.sendMessage` acts as a broadcast to
|
4
4
|
* all open extension pages, so the receiver needs a way to figure out if the
|
@@ -22,7 +22,7 @@ import { type AnyTarget, type KnownTarget, type TopLevelFrame, type MessengerMet
|
|
22
22
|
export declare const thisTarget: KnownTarget;
|
23
23
|
declare let tabDataStatus: "needed" | "pending" | "received" | "not-needed" | "error";
|
24
24
|
export declare function getTabDataStatus(): typeof tabDataStatus;
|
25
|
-
export declare function __getTabData(this: MessengerMeta):
|
25
|
+
export declare function __getTabData(this: MessengerMeta): LooseTarget;
|
26
26
|
export declare function getThisFrame(): Promise<FrameTarget>;
|
27
27
|
export declare function getTopLevelFrame(): Promise<TopLevelFrame>;
|
28
28
|
export declare function initPrivateApi(): void;
|
package/distribution/types.d.ts
CHANGED
@@ -10,7 +10,7 @@ declare global {
|
|
10
10
|
_: Method;
|
11
11
|
}
|
12
12
|
}
|
13
|
-
type WithTarget<Method> = Method extends (...args: infer PreviousArguments) => infer TReturnValue ? (target:
|
13
|
+
type WithTarget<Method> = Method extends (...args: infer PreviousArguments) => infer TReturnValue ? (target: AnyTarget, ...args: PreviousArguments) => TReturnValue : never;
|
14
14
|
type ActuallyOmitThisParameter<T> = T extends (...args: infer A) => infer R ? (...args: A) => R : T;
|
15
15
|
/** Removes the `this` type and ensure it's always Promised */
|
16
16
|
export type PublicMethod<Method extends ValueOf<MessengerMethods>> = Asyncify<ActuallyOmitThisParameter<Method>>;
|
@@ -43,7 +43,7 @@ export interface Options {
|
|
43
43
|
export type Message<LocalArguments extends Arguments = Arguments> = {
|
44
44
|
type: keyof MessengerMethods;
|
45
45
|
args: LocalArguments;
|
46
|
-
target:
|
46
|
+
target: AnyTarget;
|
47
47
|
/** If the message is being sent to an intermediary receiver, also set the options */
|
48
48
|
options?: Options;
|
49
49
|
};
|
@@ -55,7 +55,8 @@ export type MessengerMessage = Message & {
|
|
55
55
|
/** Guarantees that a message is meant to be handled by this library */
|
56
56
|
__webextMessenger: true;
|
57
57
|
};
|
58
|
-
|
58
|
+
/** A loose union to simplify the internal checks. */
|
59
|
+
export interface LooseTarget {
|
59
60
|
tabId?: number | "this";
|
60
61
|
frameId?: number | "allFrames";
|
61
62
|
page?: string;
|
@@ -85,5 +86,5 @@ export interface PageTarget {
|
|
85
86
|
export interface ExtensionTarget {
|
86
87
|
extensionId: string;
|
87
88
|
}
|
88
|
-
export type
|
89
|
+
export type AnyTarget = Target | PageTarget | ExtensionTarget;
|
89
90
|
export {};
|