diff --git a/extension/src/app/api/filters.ts b/extension/src/app/api/filters.ts
index 85d01559..3bcb356d 100644
--- a/extension/src/app/api/filters.ts
+++ b/extension/src/app/api/filters.ts
@@ -44,31 +44,41 @@ export const noFiltersApplied = (localFilter: LocalFilter | undefined) =>
!window.devToolsOptions.filter ||
window.devToolsOptions.filter === FilterState.DO_NOT_FILTER);
-export function isFiltered(action, localFilter: LocalFilter | undefined) {
+export function isFiltered>(
+ action: A | string,
+ localFilter: LocalFilter | undefined
+) {
if (
noFiltersApplied(localFilter) ||
- (typeof action !== 'string' && typeof action.type.match !== 'function')
+ (typeof action !== 'string' &&
+ typeof (action.type as string).match !== 'function')
) {
return false;
}
const { whitelist, blacklist } = localFilter || window.devToolsOptions || {};
- const actionType = action.type || action;
+ const actionType = ((action as A).type || action) as string;
return (
(whitelist && !actionType.match(whitelist)) ||
(blacklist && actionType.match(blacklist))
);
}
-function filterActions(actionsById, actionSanitizer) {
+function filterActions>(
+ actionsById: { [p: number]: PerformAction },
+ actionSanitizer: ((action: A, id: number) => A) | undefined
+) {
if (!actionSanitizer) return actionsById;
- return mapValues(actionsById, (action, id) => ({
+ return mapValues(actionsById, (action, id: number) => ({
...action,
action: actionSanitizer(action.action, id),
}));
}
-function filterStates(computedStates, stateSanitizer) {
+function filterStates(
+ computedStates: { state: S; error?: string | undefined }[],
+ stateSanitizer: ((state: S, index: number) => S) | undefined
+) {
if (!stateSanitizer) return computedStates;
return computedStates.map((state, idx) => ({
...state,
diff --git a/extension/src/app/api/index.ts b/extension/src/app/api/index.ts
index 6015b6b4..cee9ea49 100644
--- a/extension/src/app/api/index.ts
+++ b/extension/src/app/api/index.ts
@@ -7,9 +7,16 @@ import importState from './importState';
import generateId from './generateInstanceId';
import { Config } from '../../browser/extension/inject/pageScript';
import { Action } from 'redux';
-import { LiftedState, PerformAction } from '@redux-devtools/instrument';
+import {
+ EnhancedStore,
+ LiftedState,
+ PerformAction,
+} from '@redux-devtools/instrument';
import { LibConfig } from '@redux-devtools/app/lib/actions';
-import { ContentScriptToPageScriptMessage } from '../../browser/extension/inject/contentScript';
+import {
+ ContentScriptToPageScriptMessage,
+ ListenerMessage,
+} from '../../browser/extension/inject/contentScript';
import { Position } from './openWindow';
const listeners: {
@@ -267,19 +274,23 @@ function getStackTrace(
return stack;
}
-function amendActionType(
- action,
- config,
+function amendActionType>(
+ action: A | StructuralPerformAction | string,
+ config: Config,
toExcludeFromTrace: Function | undefined
-) {
+): StructuralPerformAction {
let timestamp = Date.now();
let stack = getStackTrace(config, toExcludeFromTrace);
if (typeof action === 'string') {
- return { action: { type: action }, timestamp, stack };
+ return { action: { type: action } as A, timestamp, stack };
}
- if (!action.type) return { action: { type: 'update' }, timestamp, stack };
- if (action.action) return stack ? { stack, ...action } : action;
- return { action, timestamp, stack };
+ if (!(action as A).type)
+ return { action: { type: 'update' } as A, timestamp, stack };
+ if ((action as StructuralPerformAction).action)
+ return (
+ stack ? { stack, ...action } : action
+ ) as StructuralPerformAction;
+ return { action, timestamp, stack } as StructuralPerformAction;
}
interface LiftedMessage {
@@ -305,12 +316,26 @@ interface ExportMessage> {
readonly instanceId: number;
}
+interface StructuralPerformAction> {
+ readonly action: A;
+ readonly timestamp?: number;
+ readonly stack?: string;
+}
+
+type SingleUserAction> =
+ | PerformAction
+ | StructuralPerformAction
+ | A;
+type UserAction> =
+ | SingleUserAction
+ | readonly SingleUserAction[];
+
interface ActionMessage> {
readonly type: 'ACTION';
readonly payload: S;
readonly source: typeof source;
readonly instanceId: number;
- readonly action: PerformAction | A;
+ readonly action: UserAction;
readonly maxAge: number;
readonly nextActionId: number;
}
@@ -407,9 +432,9 @@ export function toContentScript>(
}
}
-export function sendMessage(
- action,
- state,
+export function sendMessage>(
+ action: StructuralPerformAction | StructuralPerformAction[],
+ state: S,
config: Config,
instanceId?: number,
name?: string
@@ -459,18 +484,22 @@ export function setListener(
}
const liftListener =
- (listener, config: Config) => (message: ContentScriptToPageScriptMessage) => {
- let data = {};
+ >(
+ listener: (message: ListenerMessage) => void,
+ config: Config
+ ) =>
+ (message: ContentScriptToPageScriptMessage) => {
if (message.type === 'IMPORT') {
- data.type = 'DISPATCH';
- data.payload = {
- type: 'IMPORT_STATE',
- ...importState(message.state, config),
- };
+ listener({
+ type: 'DISPATCH',
+ payload: {
+ type: 'IMPORT_STATE',
+ ...importState(message.state, config),
+ },
+ });
} else {
- data = message;
+ listener(message);
}
- listener(data);
};
export function disconnect() {
@@ -493,8 +522,8 @@ export function connect(preConfig: Config) {
const localFilter = getLocalFilter(config);
const autoPause = config.autoPause;
let isPaused = autoPause;
- let delayedActions = [];
- let delayedStates = [];
+ let delayedActions: StructuralPerformAction>[] = [];
+ let delayedStates: unknown[] = [];
const rootListener = (action: ContentScriptToPageScriptMessage) => {
if (autoPause) {
@@ -517,7 +546,9 @@ export function connect(preConfig: Config) {
listeners[id] = [rootListener];
- const subscribe = (listener) => {
+ const subscribe = >(
+ listener: (message: ListenerMessage) => void
+ ) => {
if (!listener) return undefined;
const liftedListener = liftListener(listener, config);
const listenersForId = listeners[id] as ((
@@ -541,7 +572,7 @@ export function connect(preConfig: Config) {
delayedStates = [];
}, latency);
- const send = (action, state) => {
+ const send = >(action: A, state: S) => {
if (
isPaused ||
isFiltered(action, localFilter) ||
@@ -550,7 +581,7 @@ export function connect(preConfig: Config) {
return;
}
- let amendedAction = action;
+ let amendedAction: A | StructuralPerformAction = action;
const amendedState = config.stateSanitizer
? config.stateSanitizer(state)
: state;
@@ -561,7 +592,7 @@ export function connect(preConfig: Config) {
amendedAction = {
action: { type: amendedAction },
timestamp: Date.now(),
- };
+ } as unknown as A;
}
} else if (config.actionSanitizer) {
amendedAction = config.actionSanitizer(action);
@@ -624,8 +655,15 @@ export function connect(preConfig: Config) {
};
}
-export function updateStore(stores) {
- return function (newStore, instanceId) {
+export function updateStore>(
+ stores: {
+ [K in string | number]: EnhancedStore, unknown>;
+ }
+) {
+ return function (
+ newStore: EnhancedStore, unknown>,
+ instanceId: number
+ ) {
/* eslint-disable no-console */
console.warn(
'`__REDUX_DEVTOOLS_EXTENSION__.updateStore` is deprecated, remove it and just use ' +
diff --git a/extension/src/browser/extension/inject/contentScript.ts b/extension/src/browser/extension/inject/contentScript.ts
index f163ddff..e960c0d5 100644
--- a/extension/src/browser/extension/inject/contentScript.ts
+++ b/extension/src/browser/extension/inject/contentScript.ts
@@ -14,6 +14,7 @@ import {
CustomAction,
DispatchAction as AppDispatchAction,
} from '@redux-devtools/app/lib/actions';
+import { LiftedState } from '@redux-devtools/instrument';
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
@@ -90,6 +91,27 @@ export type ContentScriptToPageScriptMessage =
| ExportAction
| UpdateAction;
+interface ImportStatePayload> {
+ readonly type: 'IMPORT_STATE';
+ readonly nextLiftedState: LiftedState | readonly A[];
+ readonly preloadedState?: S;
+}
+
+interface ImportStateDispatchAction> {
+ readonly type: 'DISPATCH';
+ readonly payload: ImportStatePayload;
+}
+
+export type ListenerMessage> =
+ | StartAction
+ | StopAction
+ | DispatchAction
+ | ImportAction
+ | ActionAction
+ | ExportAction
+ | UpdateAction
+ | ImportStateDispatchAction;
+
function postToPageScript(message: ContentScriptToPageScriptMessage) {
window.postMessage(message, '*');
}
diff --git a/extension/src/browser/extension/inject/pageScript.ts b/extension/src/browser/extension/inject/pageScript.ts
index 930f655e..29252275 100644
--- a/extension/src/browser/extension/inject/pageScript.ts
+++ b/extension/src/browser/extension/inject/pageScript.ts
@@ -47,7 +47,7 @@ import { Features } from '@redux-devtools/app/lib/reducers/instances';
const source = '@devtools-page';
let stores: {
- [instanceId: number]: EnhancedStore, unknown>;
+ [K in string | number]: EnhancedStore, unknown>;
} = {};
let reportId: string | null | undefined;
@@ -80,12 +80,12 @@ export interface ConfigWithExpandedMaxAge {
readonly statesFilter?: (state: S, index?: number) => S;
readonly actionsFilter?: >(
action: A,
- id: number
+ id?: number
) => A;
readonly stateSanitizer?: (state: S, index?: number) => S;
readonly actionSanitizer?: >(
action: A,
- id: number
+ id?: number
) => A;
readonly predicate?: >(
state: S,
@@ -114,6 +114,7 @@ export interface ConfigWithExpandedMaxAge {
readonly autoPause?: boolean;
readonly features?: Features;
readonly type?: string;
+ readonly getActionType?: >(action: A) => A;
}
export interface Config extends ConfigWithExpandedMaxAge {