aboutsummaryrefslogtreecommitdiff
path: root/extension/src/webext-bridge/internal/post-message.ts
diff options
context:
space:
mode:
Diffstat (limited to 'extension/src/webext-bridge/internal/post-message.ts')
-rw-r--r--extension/src/webext-bridge/internal/post-message.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/extension/src/webext-bridge/internal/post-message.ts b/extension/src/webext-bridge/internal/post-message.ts
new file mode 100644
index 0000000..9db4424
--- /dev/null
+++ b/extension/src/webext-bridge/internal/post-message.ts
@@ -0,0 +1,52 @@
+import type { InternalMessage } from '../types'
+import { getMessagePort } from './message-port'
+
+export interface EndpointWontRespondError {
+ type: 'error'
+ transactionID: string
+}
+
+export const usePostMessaging = (thisContext: 'window' | 'content-script') => {
+ let allocatedNamespace: string
+ let messagingEnabled = false
+ let onMessageCallback: (
+ msg: InternalMessage | EndpointWontRespondError
+ ) => void
+ let portP: Promise<MessagePort>
+
+ return {
+ enable: () => (messagingEnabled = true),
+ onMessage: (cb: typeof onMessageCallback) => (onMessageCallback = cb),
+ postMessage: async(msg: InternalMessage | EndpointWontRespondError) => {
+ if (thisContext !== 'content-script' && thisContext !== 'window')
+ throw new Error('Endpoint does not use postMessage')
+
+ if (!messagingEnabled)
+ throw new Error('Communication with window has not been allowed')
+
+ ensureNamespaceSet(allocatedNamespace)
+
+ return (await portP).postMessage(msg)
+ },
+ setNamespace: (nsps: string) => {
+ if (allocatedNamespace)
+ throw new Error('Namespace once set cannot be changed')
+
+ allocatedNamespace = nsps
+ portP = getMessagePort(thisContext, nsps, ({ data }) =>
+ onMessageCallback?.(data),
+ )
+ },
+ }
+}
+
+function ensureNamespaceSet(namespace: string) {
+ if (typeof namespace !== 'string' || namespace.trim().length === 0) {
+ throw new Error(
+ 'webext-bridge uses window.postMessage to talk with other "window"(s) for message routing'
+ + 'which is global/conflicting operation in case there are other scripts using webext-bridge. '
+ + 'Call Bridge#setNamespace(nsps) to isolate your app. Example: setNamespace(\'com.facebook.react-devtools\'). '
+ + 'Make sure to use same namespace across all your scripts whereever window.postMessage is likely to be used`',
+ )
+ }
+}