mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-27 08:30:02 +03:00
Define page script to content script messages
This commit is contained in:
parent
425c78b8fc
commit
eb35441e17
|
@ -139,6 +139,7 @@ export interface PartialLiftedState<S, A extends Action<unknown>> {
|
|||
readonly stagedActionIds: readonly number[];
|
||||
readonly currentStateIndex: number;
|
||||
readonly nextActionId: number;
|
||||
readonly committedState?: S;
|
||||
}
|
||||
|
||||
export function startingFrom<S, A extends Action<unknown>>(
|
||||
|
|
|
@ -5,7 +5,6 @@ import { getActionsArray } from '@redux-devtools/utils';
|
|||
import { getLocalFilter, isFiltered, PartialLiftedState } from './filters';
|
||||
import importState from './importState';
|
||||
import generateId from './generateInstanceId';
|
||||
import { PageScriptToContentScriptMessage } from '../../browser/extension/inject/contentScript';
|
||||
import { Config } from '../../browser/extension/inject/pageScript';
|
||||
import { Action } from 'redux';
|
||||
import { LiftedState, PerformAction } from '@redux-devtools/instrument';
|
||||
|
@ -107,7 +106,100 @@ export function getSerializeParameter(
|
|||
return value;
|
||||
}
|
||||
|
||||
function post(message: PageScriptToContentScriptMessage) {
|
||||
interface InitInstancePageScriptToContentScriptMessage {
|
||||
readonly type: 'INIT_INSTANCE';
|
||||
readonly instanceId: number;
|
||||
readonly source: typeof source;
|
||||
}
|
||||
|
||||
interface DisconnectMessage {
|
||||
readonly type: 'DISCONNECT';
|
||||
readonly source: typeof source;
|
||||
}
|
||||
|
||||
interface InitMessage<S, A extends Action<unknown>> {
|
||||
readonly type: 'INIT';
|
||||
readonly payload: string;
|
||||
readonly instanceId: number;
|
||||
readonly source: typeof source;
|
||||
action?: string;
|
||||
name?: string | undefined;
|
||||
liftedState?: LiftedState<S, A, unknown>;
|
||||
libConfig?: unknown;
|
||||
}
|
||||
|
||||
interface SerializedPartialLiftedState<S, A extends Action<unknown>> {
|
||||
readonly stagedActionIds: readonly number[];
|
||||
readonly currentStateIndex: number;
|
||||
readonly nextActionId: number;
|
||||
}
|
||||
|
||||
interface SerializedPartialStateMessage<S, A extends Action<unknown>> {
|
||||
readonly type: 'PARTIAL_STATE';
|
||||
readonly payload: SerializedPartialLiftedState<S, A>;
|
||||
readonly source: typeof source;
|
||||
readonly instanceId: number;
|
||||
readonly maxAge: number;
|
||||
readonly actionsById: string;
|
||||
readonly computedStates: string;
|
||||
readonly committedState: boolean;
|
||||
}
|
||||
|
||||
interface SerializedExportMessage {
|
||||
readonly type: 'EXPORT';
|
||||
readonly payload: string;
|
||||
readonly committedState: string | undefined;
|
||||
readonly source: typeof source;
|
||||
readonly instanceId: number;
|
||||
}
|
||||
|
||||
interface SerializedActionMessage {
|
||||
readonly type: 'ACTION';
|
||||
readonly payload: string;
|
||||
readonly source: typeof source;
|
||||
readonly instanceId: number;
|
||||
readonly action: string;
|
||||
readonly maxAge: number;
|
||||
readonly nextActionId: number;
|
||||
}
|
||||
|
||||
interface SerializedStateMessage<S, A extends Action<unknown>> {
|
||||
readonly type: 'STATE';
|
||||
readonly payload: Omit<
|
||||
LiftedState<S, A, unknown>,
|
||||
'actionsById' | 'computedStates' | 'committedState'
|
||||
>;
|
||||
readonly source: typeof source;
|
||||
readonly instanceId: number;
|
||||
readonly libConfig?: unknown;
|
||||
readonly actionsById: string;
|
||||
readonly computedStates: string;
|
||||
readonly committedState: boolean;
|
||||
}
|
||||
|
||||
export type PageScriptToContentScriptMessageWithoutDisconnect<
|
||||
S,
|
||||
A extends Action<unknown>
|
||||
> =
|
||||
| InitInstancePageScriptToContentScriptMessage
|
||||
| InitMessage<S, A>
|
||||
| LiftedMessage
|
||||
| SerializedPartialStateMessage<S, A>
|
||||
| SerializedExportMessage
|
||||
| SerializedActionMessage
|
||||
| SerializedStateMessage<S, A>
|
||||
| ErrorMessage
|
||||
| InitInstanceMessage
|
||||
| GetReportMessage
|
||||
| StopMessage;
|
||||
|
||||
export type PageScriptToContentScriptMessage<S, A extends Action<unknown>> =
|
||||
| PageScriptToContentScriptMessageWithoutDisconnect<S, A>
|
||||
| DisconnectMessage;
|
||||
|
||||
function post<S, A extends Action<unknown>>(
|
||||
message: PageScriptToContentScriptMessage<S, A>
|
||||
) {
|
||||
window.postMessage(message, '*');
|
||||
}
|
||||
|
||||
|
@ -164,7 +256,7 @@ function amendActionType(
|
|||
return { action, timestamp, stack };
|
||||
}
|
||||
|
||||
interface LiftedMessage {
|
||||
export interface LiftedMessage {
|
||||
readonly type: 'LIFTED';
|
||||
readonly liftedState: { readonly isPaused: boolean };
|
||||
readonly instanceId: number;
|
||||
|
@ -250,28 +342,52 @@ export function toContentScript<S, A extends Action<unknown>>(
|
|||
serializeAction?: Serialize | undefined
|
||||
) {
|
||||
if (message.type === 'ACTION') {
|
||||
message.action = stringify(message.action, serializeAction);
|
||||
message.payload = stringify(message.payload, serializeState);
|
||||
} else if (message.type === 'STATE' || message.type === 'PARTIAL_STATE') {
|
||||
post({
|
||||
...message,
|
||||
action: stringify(message.action, serializeAction),
|
||||
payload: stringify(message.payload, serializeState),
|
||||
});
|
||||
} else if (message.type === 'STATE') {
|
||||
const { actionsById, computedStates, committedState, ...rest } =
|
||||
message.payload;
|
||||
message.payload = rest;
|
||||
message.actionsById = stringify(actionsById, serializeAction);
|
||||
message.computedStates = stringify(computedStates, serializeState);
|
||||
message.committedState = typeof committedState !== 'undefined';
|
||||
post({
|
||||
...message,
|
||||
payload: rest,
|
||||
actionsById: stringify(actionsById, serializeAction),
|
||||
computedStates: stringify(computedStates, serializeState),
|
||||
committedState: typeof committedState !== 'undefined',
|
||||
});
|
||||
} else if (message.type === 'PARTIAL_STATE') {
|
||||
const { actionsById, computedStates, committedState, ...rest } =
|
||||
message.payload;
|
||||
post({
|
||||
...message,
|
||||
payload: rest,
|
||||
actionsById: stringify(actionsById, serializeAction),
|
||||
computedStates: stringify(computedStates, serializeState),
|
||||
committedState: typeof committedState !== 'undefined',
|
||||
});
|
||||
} else if (message.type === 'EXPORT') {
|
||||
message.payload = stringify(message.payload, serializeAction);
|
||||
if (typeof message.committedState !== 'undefined') {
|
||||
message.committedState = stringify(
|
||||
message.committedState,
|
||||
serializeState
|
||||
);
|
||||
}
|
||||
post({
|
||||
...message,
|
||||
payload: stringify(message.payload, serializeAction),
|
||||
committedState:
|
||||
typeof message.committedState !== 'undefined'
|
||||
? stringify(message.committedState, serializeState)
|
||||
: (message.committedState as undefined),
|
||||
});
|
||||
} else {
|
||||
post(message);
|
||||
}
|
||||
post(message);
|
||||
}
|
||||
|
||||
export function sendMessage(action, state, config, instanceId, name) {
|
||||
export function sendMessage(
|
||||
action,
|
||||
state,
|
||||
config: Config,
|
||||
instanceId?: number,
|
||||
name?: string
|
||||
) {
|
||||
let amendedAction = action;
|
||||
if (typeof config !== 'object') {
|
||||
// Legacy: sending actions not from connected part
|
||||
|
@ -427,8 +543,11 @@ export function connect(preConfig) {
|
|||
sendMessage(amendedAction, amendedState, config);
|
||||
};
|
||||
|
||||
const init = (state, liftedData) => {
|
||||
const message = {
|
||||
const init = <S, A extends Action<unknown>>(
|
||||
state: S,
|
||||
liftedData: LiftedState<S, A, unknown>
|
||||
) => {
|
||||
const message: InitMessage<S, A> = {
|
||||
type: 'INIT',
|
||||
payload: stringify(state, config.serialize),
|
||||
instanceId: id,
|
||||
|
@ -454,8 +573,8 @@ export function connect(preConfig) {
|
|||
post(message);
|
||||
};
|
||||
|
||||
const error = (payload) => {
|
||||
post({ type: 'ERROR', payload, id, source });
|
||||
const error = (payload: unknown) => {
|
||||
post({ type: 'ERROR', payload, instanceId: id, source });
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessages, false);
|
||||
|
|
|
@ -4,6 +4,11 @@ import {
|
|||
isAllowed,
|
||||
} from '../options/syncOptions';
|
||||
import { TabMessage } from '../../../app/middlewares/api';
|
||||
import {
|
||||
PageScriptToContentScriptMessage,
|
||||
PageScriptToContentScriptMessageWithoutDisconnect,
|
||||
} from '../../../app/api';
|
||||
import { Action } from 'redux';
|
||||
const source = '@devtools-extension';
|
||||
const pageSource = '@devtools-page';
|
||||
// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts
|
||||
|
@ -64,21 +69,46 @@ function handleDisconnect() {
|
|||
bg = undefined;
|
||||
}
|
||||
|
||||
function tryCatch<A>(
|
||||
fn: (args: PageScriptToContentScriptMessage) => void,
|
||||
args: PageScriptToContentScriptMessage
|
||||
interface SplitMessageBase {
|
||||
readonly type?: never;
|
||||
}
|
||||
|
||||
interface SplitMessageStart extends SplitMessageBase {
|
||||
readonly split: 'start';
|
||||
}
|
||||
|
||||
interface SplitMessageChunk extends SplitMessageBase {
|
||||
readonly instanceId: number;
|
||||
readonly source: typeof pageSource;
|
||||
readonly split: 'chunk';
|
||||
readonly chunk: [string, string];
|
||||
}
|
||||
|
||||
interface SplitMessageEnd extends SplitMessageBase {
|
||||
readonly instanceId: number;
|
||||
readonly source: typeof pageSource;
|
||||
readonly split: 'end';
|
||||
}
|
||||
|
||||
type SplitMessage = SplitMessageStart | SplitMessageChunk | SplitMessageEnd;
|
||||
|
||||
function tryCatch<S, A extends Action<unknown>>(
|
||||
fn: (args: PageScriptToContentScriptMessage<S, A> | SplitMessage) => void,
|
||||
args: PageScriptToContentScriptMessageWithoutDisconnect<S, A>
|
||||
) {
|
||||
try {
|
||||
return fn(args);
|
||||
} catch (err) {
|
||||
if (err.message === 'Message length exceeded maximum allowed length.') {
|
||||
const instanceId = args.instanceId;
|
||||
const newArgs = { split: 'start' };
|
||||
const toSplit = [];
|
||||
const newArgs: SplitMessageStart = {
|
||||
split: 'start',
|
||||
};
|
||||
const toSplit: [string, string][] = [];
|
||||
let size = 0;
|
||||
let arg;
|
||||
Object.keys(args).map((key) => {
|
||||
arg = args[key];
|
||||
arg = args[key as keyof typeof args];
|
||||
if (typeof arg === 'string') {
|
||||
size += arg.length;
|
||||
if (size > maxChromeMsgSize) {
|
||||
|
@ -86,7 +116,7 @@ function tryCatch<A>(
|
|||
return;
|
||||
}
|
||||
}
|
||||
newArgs[key] = arg;
|
||||
newArgs[key as keyof typeof newArgs] = arg;
|
||||
});
|
||||
fn(newArgs);
|
||||
for (let i = 0; i < toSplit.length; i++) {
|
||||
|
@ -110,21 +140,6 @@ function tryCatch<A>(
|
|||
}
|
||||
}
|
||||
|
||||
interface InitInstancePageScriptToContentScriptMessage {
|
||||
readonly type: 'INIT_INSTANCE';
|
||||
readonly instanceId: number;
|
||||
readonly source: typeof pageSource;
|
||||
}
|
||||
|
||||
interface DisconnectMessage {
|
||||
readonly type: 'DISCONNECT';
|
||||
readonly source: typeof pageSource;
|
||||
}
|
||||
|
||||
export type PageScriptToContentScriptMessage =
|
||||
| InitInstancePageScriptToContentScriptMessage
|
||||
| DisconnectMessage;
|
||||
|
||||
interface InitInstanceContentScriptToBackgroundMessage {
|
||||
readonly name: 'INIT_INSTANCE';
|
||||
readonly instanceId: number;
|
||||
|
@ -143,7 +158,9 @@ function postToBackground(message: ContentScriptToBackgroundMessage) {
|
|||
bg!.postMessage(message);
|
||||
}
|
||||
|
||||
function send(message: never) {
|
||||
function send<S, A extends Action<unknown>>(
|
||||
message: PageScriptToContentScriptMessage<S, A> | SplitMessage
|
||||
) {
|
||||
if (!connected) connect();
|
||||
if (message.type === 'INIT_INSTANCE') {
|
||||
getOptionsFromBg();
|
||||
|
@ -154,7 +171,9 @@ function send(message: never) {
|
|||
}
|
||||
|
||||
// Resend messages from the page to the background script
|
||||
function handleMessages(event: MessageEvent<PageScriptToContentScriptMessage>) {
|
||||
function handleMessages<S, A extends Action<unknown>>(
|
||||
event: MessageEvent<PageScriptToContentScriptMessage<S, A>>
|
||||
) {
|
||||
if (!isAllowed()) return;
|
||||
if (!event || event.source !== window || typeof event.data !== 'object') {
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue
Block a user