From ef5fa275a32d2490e0e49b659ddf2add5a7dbeb1 Mon Sep 17 00:00:00 2001 From: Andrey Goncharov Date: Mon, 20 Jun 2022 12:18:40 -0700 Subject: [PATCH] Use AbstractClient from flipper-frontend-core in fliper-ui-core Summary: This stack attempts to start using flipper-frontend-core from flipper-ui-core. Currently, flipper-frontend-core contains lots of copy-pasted code from flipper-ui-core. Reviewed By: lblasa Differential Revision: D37139198 fbshipit-source-id: 042db7492c550e10ea72c32fd15001c141bf53f9 --- desktop/flipper-frontend-core/package.json | 2 +- .../src/AbstractClient.tsx | 43 +- desktop/flipper-frontend-core/src/index.tsx | 8 +- desktop/flipper-ui-core/package.json | 1 + desktop/flipper-ui-core/src/Client.tsx | 595 +++--------------- .../src/__tests__/PluginContainer.node.tsx | 68 +- .../src/__tests__/test-utils/MockFlipper.tsx | 7 +- desktop/flipper-ui-core/src/deeplink.tsx | 4 + .../src/dispatcher/flipperServer.tsx | 2 + .../dispatcher/handleOpenPluginDeeplink.tsx | 4 + .../src/reducers/connections.tsx | 10 + .../notification/Notification.tsx | 2 + .../src/selectors/connections.tsx | 3 +- .../src/utils/__tests__/exportData.node.tsx | 26 + .../flipper-ui-core/src/utils/exportData.tsx | 33 +- desktop/flipper-ui-core/tsconfig.json | 3 + desktop/jest.config.js | 3 +- desktop/plugins/public/layout/index.tsx | 1 + desktop/yarn.lock | 32 - 19 files changed, 251 insertions(+), 596 deletions(-) diff --git a/desktop/flipper-frontend-core/package.json b/desktop/flipper-frontend-core/package.json index 3f529fffd..ee1237d7d 100644 --- a/desktop/flipper-frontend-core/package.json +++ b/desktop/flipper-frontend-core/package.json @@ -15,7 +15,7 @@ "flipper-plugin": "0.0.0", "immer": "^9.0.12", "js-base64": "^3.7.2", - "p-map": "^5.3.0", + "p-map": "^4.0.0", "reconnecting-websocket": "^4.4.0", "semver": "^7.3.7" }, diff --git a/desktop/flipper-frontend-core/src/AbstractClient.tsx b/desktop/flipper-frontend-core/src/AbstractClient.tsx index 48b6d5638..4cfe3a5cd 100644 --- a/desktop/flipper-frontend-core/src/AbstractClient.tsx +++ b/desktop/flipper-frontend-core/src/AbstractClient.tsx @@ -37,11 +37,6 @@ import isProduction from './utils/isProduction'; type Plugins = Set; type PluginsArr = Array; -export type ClientExport = { - id: string; - query: ClientQuery; -}; - export type Params = { api: string; method: string; @@ -108,7 +103,7 @@ export default abstract class AbstractClient extends EventEmitter { protected abstract shouldConnectAsBackgroundPlugin(pluginId: string): boolean; async init() { - await this.loadPlugins(); + await this.loadPlugins('init'); await Promise.all( [...this.plugins].map(async (pluginId) => this.startPluginIfNeeded(await this.getPlugin(pluginId)), @@ -124,7 +119,7 @@ export default abstract class AbstractClient extends EventEmitter { } // get the supported plugins - protected async loadPlugins(): Promise { + protected async loadPlugins(_phase: 'init' | 'refresh'): Promise { const {plugins} = await timeout( 30 * 1000, this.rawCall<{plugins: Plugins}>('getPlugins', false), @@ -204,9 +199,9 @@ export default abstract class AbstractClient extends EventEmitter { } // get the plugins, and update the UI - protected async refreshPlugins() { + async refreshPlugins() { const oldBackgroundPlugins = this.backgroundPlugins; - await this.loadPlugins(); + await this.loadPlugins('refresh'); await Promise.all( [...this.plugins].map(async (pluginId) => this.startPluginIfNeeded(await this.getPlugin(pluginId)), @@ -291,13 +286,7 @@ export default abstract class AbstractClient extends EventEmitter { ); } - const pluginInstance = this.getPluginInstanceForExecuteMessage(params); - - let handled = false; // This is just for analysis - if (pluginInstance) { - handled = true; - pluginInstance.receiveMessages([params]); - } + const handled = this.handleExecuteMessage(params); if (!handled && !isProduction()) { console.warn(`Unhandled message ${params.api}.${params.method}`); } @@ -307,10 +296,13 @@ export default abstract class AbstractClient extends EventEmitter { } } - protected getPluginInstanceForExecuteMessage( - params: Params, - ): _SandyPluginInstance | undefined { - return this.sandyPluginStates.get(params.api); + protected handleExecuteMessage(params: Params): boolean { + const pluginInstance = this.sandyPluginStates.get(params.api); + if (!pluginInstance) { + return false; + } + pluginInstance.receiveMessages([params]); + return true; } protected onResponse( @@ -502,6 +494,17 @@ export default abstract class AbstractClient extends EventEmitter { ); } + send(api: string, method: string, params?: Object): void { + if (!isProduction()) { + console.warn( + `${api}:${ + method || '' + } client.send() is deprecated. Please use call() instead so you can handle errors.`, + ); + } + return this.rawSend('execute', {api, method, params}); + } + async supportsMethod(api: string, method: string): Promise { if (!this.connected.get()) { return false; diff --git a/desktop/flipper-frontend-core/src/index.tsx b/desktop/flipper-frontend-core/src/index.tsx index 2beca1acb..cd488eafe 100644 --- a/desktop/flipper-frontend-core/src/index.tsx +++ b/desktop/flipper-frontend-core/src/index.tsx @@ -8,10 +8,16 @@ */ export {RenderHost, getRenderHostInstance} from './RenderHost'; -export {default as AbstractClient, ClientConnection} from './AbstractClient'; +export { + default as AbstractClient, + ClientConnection, + Params, + RequestMetadata, +} from './AbstractClient'; export {default as ArchivedDevice} from './devices/ArchivedDevice'; export {default as BaseDevice} from './devices/BaseDevice'; export * from './globalObject'; export * from './plugins'; +export {getPluginKey} from './utils/pluginKey'; export * from './flipperLibImplementation'; export * from './client/FlipperServerClient'; diff --git a/desktop/flipper-ui-core/package.json b/desktop/flipper-ui-core/package.json index 210653e9c..0b0b308e0 100644 --- a/desktop/flipper-ui-core/package.json +++ b/desktop/flipper-ui-core/package.json @@ -22,6 +22,7 @@ "eventemitter3": "^4.0.7", "flipper-client-sdk": "^0.0.3", "flipper-common": "0.0.0", + "flipper-frontend-core": "0.0.0", "flipper-plugin": "0.0.0", "flipper-ui-core": "0.0.0", "hotkeys-js": "^3.9.3", diff --git a/desktop/flipper-ui-core/src/Client.tsx b/desktop/flipper-ui-core/src/Client.tsx index 62431c24a..e34ee694b 100644 --- a/desktop/flipper-ui-core/src/Client.tsx +++ b/desktop/flipper-ui-core/src/Client.tsx @@ -10,63 +10,40 @@ // We're using `deviceSync` here on purpose which is triggering a lot of warnings. /* eslint-disable node/no-sync */ -import {PluginDefinition} from './plugin'; -import BaseDevice from './devices/BaseDevice'; -import {Logger, FlipperServer, ServerAddOnControls} from 'flipper-common'; -import {Store} from './reducers/index'; import { - reportPluginFailures, - NoLongerConnectedToClientError, + Logger, + FlipperServer, + ClientQuery, + ClientErrorType, } from 'flipper-common'; -import {default as isProduction} from './utils/isProduction'; -import EventEmitter from 'eventemitter3'; -import {getPluginKey} from './utils/pluginKey'; - +import {Store} from './reducers/index'; +import {NoLongerConnectedToClientError} from 'flipper-common'; import {defaultEnabledBackgroundPlugins} from './utils/pluginUtils'; import {processMessagesLater} from './utils/messageQueue'; import {emitBytesReceived} from './dispatcher/tracking'; import {debounce} from 'lodash'; import {batch} from 'react-redux'; -import { - timeout, - ClientQuery, - ClientResponseType, - ClientErrorType, -} from 'flipper-common'; -import { - createState, - _SandyPluginInstance, - getFlipperLib, - _SandyPluginDefinition, -} from 'flipper-plugin'; -import {freeze} from 'immer'; +import {_SandyPluginInstance, _SandyPluginDefinition} from 'flipper-plugin'; import {message} from 'antd'; import { isFlipperMessageDebuggingEnabled, registerFlipperDebugMessage, } from './chrome/FlipperMessages'; import {waitFor} from './utils/waitFor'; -import {createServerAddOnControls} from './utils/createServerAddOnControls'; - -type Plugins = Set; -type PluginsArr = Array; +import { + AbstractClient, + Params, + ClientConnection, + BaseDevice, + RequestMetadata, + getPluginKey, +} from 'flipper-frontend-core'; export type ClientExport = { id: string; query: ClientQuery; }; -export type Params = { - api: string; - method: string; - params?: Object; -}; -export type RequestMetadata = { - method: string; - id: number; - params: Params | undefined; -}; - const handleError = ( store: Store, device: BaseDevice, @@ -97,25 +74,8 @@ const handleError = ( crashReporterPlugin.instanceApi.reportCrash(payload); }; -export interface ClientConnection { - send(data: any): void; - sendExpectResponse(data: any): Promise; -} - -export default class Client extends EventEmitter { - connected = createState(false); - id: string; - query: ClientQuery; - sdkVersion: number; - messageIdCounter: number; - plugins: Plugins; // TODO: turn into atom, and remove eventEmitter - backgroundPlugins: Plugins; - connection: ClientConnection | null | undefined; +export default class Client extends AbstractClient { store: Store; - activePlugins: Set; - - device: BaseDevice; - logger: Logger; broadcastCallbacks: Map>>; messageBuffer: Record< string /*pluginKey*/, @@ -124,9 +84,6 @@ export default class Client extends EventEmitter { messages: Params[]; } > = {}; - sandyPluginStates = new Map(); - private readonly serverAddOnControls: ServerAddOnControls; - private readonly flipperServer: FlipperServer; constructor( id: string, @@ -134,36 +91,29 @@ export default class Client extends EventEmitter { conn: ClientConnection | null | undefined, logger: Logger, store: Store, - plugins: Plugins | null | undefined, + plugins: Set | null | undefined, device: BaseDevice, flipperServer: FlipperServer, ) { - super(); - this.connected.set(!!conn); - this.plugins = plugins ? plugins : new Set(); - this.backgroundPlugins = new Set(); - this.connection = conn; - this.id = id; - this.query = query; - this.sdkVersion = query.sdk_version || 0; - this.messageIdCounter = 0; - this.logger = logger; + super(id, query, conn, logger, plugins, device, flipperServer); this.store = store; this.broadcastCallbacks = new Map(); - this.activePlugins = new Set(); - this.device = device; - this.flipperServer = flipperServer; - this.serverAddOnControls = createServerAddOnControls(this.flipperServer); + + this.on('flipper-debug-message', (message) => { + if (isFlipperMessageDebuggingEnabled()) { + registerFlipperDebugMessage(message); + } + }); + + this.on('bytes-received', (api, bytes) => emitBytesReceived(api, bytes)); + + this.on('error', (error) => handleError(this.store, this.device, error)); } supportsPlugin(pluginId: string): boolean { return this.plugins.has(pluginId); } - isBackgroundPlugin(pluginId: string) { - return this.backgroundPlugins.has(pluginId); - } - isEnabledPlugin(pluginId: string) { return this.store .getState() @@ -177,77 +127,41 @@ export default class Client extends EventEmitter { ); } - async init() { - await this.loadPlugins(); - // if a client arrives before all plugins are loaded, we'll have to wait - await waitFor(this.store, (state) => state.plugins.initialized); - // this starts all sandy enabled plugins - this.plugins.forEach((pluginId) => - this.startPluginIfNeeded(this.getPlugin(pluginId)), + async initFromImport( + initialStates: Record>, + ): Promise { + await Promise.all( + [...this.plugins].map(async (pluginId) => { + const plugin = await this.getPlugin(pluginId); + if (plugin) { + this.loadPlugin(plugin, initialStates[pluginId]); + } + }), ); - this.backgroundPlugins = new Set(await this.getBackgroundPlugins()); - this.backgroundPlugins.forEach((plugin) => { - if (this.shouldConnectAsBackgroundPlugin(plugin)) { - this.initPlugin(plugin); - } - }); - this.emit('plugins-change'); - } - - initFromImport(initialStates: Record>): this { - this.plugins.forEach((pluginId) => { - const plugin = this.getPlugin(pluginId); - if (plugin) { - this.loadPlugin(plugin, initialStates[pluginId]); - } - }); this.emit('plugins-change'); return this; } // get the supported plugins - async loadPlugins(): Promise { - const {plugins} = await timeout( - 30 * 1000, - this.rawCall<{plugins: Plugins}>('getPlugins', false), - 'Fetch plugin timeout for ' + this.id, - ); - this.plugins = new Set(plugins); + async loadPlugins(phase: 'init' | 'refresh'): Promise> { + const plugins = await super.loadPlugins(phase); + if (phase === 'init') { + // if a client arrives before all plugins are loaded, we'll have to wait + await waitFor(this.store, (state) => state.plugins.initialized); + } return plugins; } - loadPlugin( - plugin: _SandyPluginDefinition, - initialState?: Record, - ) { - try { - this.sandyPluginStates.set( - plugin.id, - new _SandyPluginInstance( - this.serverAddOnControls, - getFlipperLib(), - plugin, - this, - getPluginKey(this.id, {serial: this.query.device_id}, plugin.id), - initialState, - ), - ); - } catch (e) { - console.error(`Failed to start plugin '${plugin.id}': `, e); - } - } - startPluginIfNeeded( - plugin: PluginDefinition | undefined, + plugin: _SandyPluginDefinition | undefined, isEnabled = plugin ? this.isEnabledPlugin(plugin.id) : false, ) { // start a plugin on start if it is a SandyPlugin, which is enabled, and doesn't have persisted state yet if ( plugin && - (isEnabled || defaultEnabledBackgroundPlugins.includes(plugin.id)) && - !this.sandyPluginStates.has(plugin.id) + (isEnabled || defaultEnabledBackgroundPlugins.includes(plugin.id)) ) { - this.loadPlugin(plugin); + super.startPluginIfNeeded(plugin); } } @@ -261,207 +175,65 @@ export default class Client extends EventEmitter { pluginId, ); delete this.messageBuffer[pluginKey]; - const instance = this.sandyPluginStates.get(pluginId); - if (instance) { - instance.destroy(); - this.sandyPluginStates.delete(pluginId); - } - } - - // connection lost, but Client might live on - disconnect() { - this.sandyPluginStates.forEach((instance) => { - instance.disconnect(); - }); - this.emit('close'); - this.connected.set(false); - } - - // clean up this client - destroy() { - this.disconnect(); - this.plugins.forEach((pluginId) => this.stopPluginIfNeeded(pluginId, true)); - this.serverAddOnControls.unsubscribe(); + return super.stopPluginIfNeeded(pluginId, force); } // gets a plugin by pluginId - getPlugin(pluginId: string): PluginDefinition | undefined { + protected async getPlugin( + pluginId: string, + ): Promise<_SandyPluginDefinition | undefined> { const plugins = this.store.getState().plugins; return ( plugins.clientPlugins.get(pluginId) || plugins.devicePlugins.get(pluginId) ); } - // get the supported background plugins - async getBackgroundPlugins(): Promise { - if (this.sdkVersion < 4) { - return []; - } - const data = await timeout( - 30 * 1000, - this.rawCall<{plugins: PluginsArr}>('getBackgroundPlugins', false), - 'Fetch background plugins timeout for ' + this.id, - ); - return data.plugins; - } - - // get the plugins, and update the UI - async refreshPlugins() { - const oldBackgroundPlugins = this.backgroundPlugins; - await this.loadPlugins(); - this.plugins.forEach((pluginId) => - this.startPluginIfNeeded(this.getPlugin(pluginId)), - ); - const newBackgroundPlugins = await this.getBackgroundPlugins(); - this.backgroundPlugins = new Set(newBackgroundPlugins); - // diff the background plugin list, disconnect old, connect new ones - oldBackgroundPlugins.forEach((plugin) => { - if ( - !this.backgroundPlugins.has(plugin) && - this.store - .getState() - .connections.enabledPlugins[this.query.app]?.includes(plugin) - ) { - this.deinitPlugin(plugin); - } - }); - newBackgroundPlugins.forEach((plugin) => { - if ( - !oldBackgroundPlugins.has(plugin) && - this.shouldConnectAsBackgroundPlugin(plugin) - ) { - this.initPlugin(plugin); - } - }); - this.emit('plugins-change'); - } - onMessage(msg: string) { - if (typeof msg !== 'string') { - return; - } - batch(() => { - let rawData; - try { - rawData = freeze(JSON.parse(msg), true); - } catch (err) { - console.error(`Invalid JSON: ${msg}`, 'clientMessage'); - return; - } - - const data: { - id?: number; - method?: string; - params?: Params; - success?: Object; - error?: ClientErrorType; - } = rawData; - - const {id, method} = data; - - if (isFlipperMessageDebuggingEnabled()) { - registerFlipperDebugMessage({ - device: this.device?.displayTitle(), - app: this.query.app, - flipperInternalMethod: method, - plugin: data.params?.api, - pluginMethod: data.params?.method, - payload: data.params?.params, - direction: 'toFlipper:message', - }); - } - - if (id == null) { - const {error} = data; - if (error != null) { - console.error( - `Error received from device ${ - method ? `when calling ${method}` : '' - }: ${error.message} + \nDevice Stack Trace: ${error.stacktrace}`, - 'deviceError', - ); - handleError(this.store, this.device, error); - } else if (method === 'refreshPlugins') { - this.refreshPlugins(); - } else if (method === 'execute') { - if (!data.params) { - throw new Error('expected params'); - } - const params: Params = data.params; - const bytes = msg.length * 2; // string lengths are measured in UTF-16 units (not characters), so 2 bytes per char - emitBytesReceived(params.api, bytes); - if (bytes > 5 * 1024 * 1024) { - console.warn( - `Plugin '${params.api}' received excessively large message for '${ - params.method - }': ${Math.round(bytes / 1024)}kB`, - ); - } - - const persistingPlugin: PluginDefinition | undefined = - this.store.getState().plugins.clientPlugins.get(params.api) || - this.store.getState().plugins.devicePlugins.get(params.api); - - let handled = false; // This is just for analysis - if ( - persistingPlugin && - ((persistingPlugin as any).persistedStateReducer || - // only send messages to enabled sandy plugins - this.sandyPluginStates.has(params.api)) - ) { - handled = true; - const pluginKey = getPluginKey( - this.id, - {serial: this.query.device_id}, - params.api, - ); - if (!this.messageBuffer[pluginKey]) { - this.messageBuffer[pluginKey] = { - plugin: (this.sandyPluginStates.get(params.api) ?? - persistingPlugin) as any, - messages: [params], - }; - } else { - this.messageBuffer[pluginKey].messages.push(params); - } - this.flushMessageBufferDebounced(); - } - const apiCallbacks = this.broadcastCallbacks.get(params.api); - if (apiCallbacks) { - const methodCallbacks = apiCallbacks.get(params.method); - if (methodCallbacks) { - for (const callback of methodCallbacks) { - handled = true; - callback(params.params); - } - } - } - if (!handled && !isProduction()) { - console.warn(`Unhandled message ${params.api}.${params.method}`); - } - } - return; // method === 'execute' - } + super.onMessage(msg); }); } - onResponse( - data: ClientResponseType, - resolve: ((a: any) => any) | undefined, - reject: (error: ClientErrorType) => any, - ) { - if (data.success) { - resolve && resolve(data.success); - } else if (data.error) { - reject(data.error); - const {error} = data; - if (error) { - handleError(this.store, this.device, error); + protected handleExecuteMessage(params: Params): boolean { + const persistingPlugin: _SandyPluginDefinition | undefined = + this.store.getState().plugins.clientPlugins.get(params.api) || + this.store.getState().plugins.devicePlugins.get(params.api); + + let handled = false; // This is just for analysis + if ( + persistingPlugin && + ((persistingPlugin as any).persistedStateReducer || + // only send messages to enabled sandy plugins + this.sandyPluginStates.has(params.api)) + ) { + handled = true; + const pluginKey = getPluginKey( + this.id, + {serial: this.query.device_id}, + params.api, + ); + if (!this.messageBuffer[pluginKey]) { + this.messageBuffer[pluginKey] = { + plugin: (this.sandyPluginStates.get(params.api) ?? + persistingPlugin) as any, + messages: [params], + }; + } else { + this.messageBuffer[pluginKey].messages.push(params); } - } else { - // ??? + this.flushMessageBufferDebounced(); } + const apiCallbacks = this.broadcastCallbacks.get(params.api); + if (apiCallbacks) { + const methodCallbacks = apiCallbacks.get(params.method); + if (methodCallbacks) { + for (const callback of methodCallbacks) { + handled = true; + callback(params.params); + } + } + } + return handled; } toJSON(): ClientExport { @@ -497,82 +269,15 @@ export default class Client extends EventEmitter { } rawCall(method: string, fromPlugin: boolean, params?: Params): Promise { - return new Promise(async (resolve, reject) => { - const id = this.messageIdCounter++; - const metadata: RequestMetadata = { - method, - id, - params, - }; - - const data = { - id, - method, - params, - }; - - const plugin = params ? params.api : undefined; - - console.debug(data, 'message:call'); - - const mark = this.getPerformanceMark(metadata); - performance.mark(mark); - if (!this.connected.get()) { + return super.rawCall(method, fromPlugin, params).catch((error) => { + if (error instanceof NoLongerConnectedToClientError) { message.warn({ content: 'Not connected', key: 'appnotconnectedwarning', duration: 0.5, }); - reject(new NoLongerConnectedToClientError()); - return; - } - if (!fromPlugin || this.isAcceptingMessagesFromPlugin(plugin)) { - try { - const response = await this.connection!.sendExpectResponse(data); - if (!fromPlugin || this.isAcceptingMessagesFromPlugin(plugin)) { - const logEventName = this.getLogEventName(data); - this.logger.trackTimeSince(mark, logEventName); - emitBytesReceived(plugin || 'unknown', response.length * 2); - - this.onResponse(response, resolve, reject); - - if (isFlipperMessageDebuggingEnabled()) { - registerFlipperDebugMessage({ - device: this.device?.displayTitle(), - app: this.query.app, - flipperInternalMethod: method, - payload: response, - plugin, - pluginMethod: params?.method, - direction: 'toFlipper:response', - }); - } - } - } catch (error) { - // This is only called if the connection is dead. Not in expected - // and recoverable cases like a missing receiver/method. - this.disconnect(); - reject(new Error('Unable to send, connection error: ' + error)); - } - } else { - reject( - new Error( - `Cannot send ${method}, client is not accepting messages for plugin ${plugin}`, - ), - ); - } - - if (isFlipperMessageDebuggingEnabled()) { - registerFlipperDebugMessage({ - device: this.device?.displayTitle(), - app: this.query.app, - flipperInternalMethod: method, - plugin: params?.api, - pluginMethod: params?.method, - payload: params?.params, - direction: 'toClient:call', - }); } + throw error; }); } @@ -605,118 +310,4 @@ export default class Client extends EventEmitter { const logEventName = this.getLogEventName(data); this.logger.trackTimeSince(mark, logEventName); } - - isAcceptingMessagesFromPlugin(plugin: string | null | undefined) { - return this.connection && (!plugin || this.activePlugins.has(plugin)); - } - - getPerformanceMark(data: RequestMetadata): string { - const {method, id} = data; - return `request_response_${method}_${id}`; - } - - getLogEventName(data: RequestMetadata): string { - const {method, params} = data; - return params && params.api && params.method - ? `request_response_${method}_${params.api}_${params.method}` - : `request_response_${method}`; - } - - initPlugin(pluginId: string) { - this.activePlugins.add(pluginId); - const instance = this.sandyPluginStates.get(pluginId); - if (this.connected.get() && instance) { - this.rawSend('init', {plugin: pluginId}); - instance.connect(); - } - } - - deinitPlugin(pluginId: string) { - this.activePlugins.delete(pluginId); - const instance = this.sandyPluginStates.get(pluginId); - instance?.disconnect(); - if (this.connected.get() && instance) { - this.rawSend('deinit', {plugin: pluginId}); - } - } - - rawSend(method: string, params?: Object): void { - const data = { - method, - params, - }; - console.debug(data, 'message:send'); - if (this.connection) { - this.connection.send(data); - } - - if (isFlipperMessageDebuggingEnabled()) { - registerFlipperDebugMessage({ - device: this.device?.displayTitle(), - app: this.query.app, - flipperInternalMethod: method, - payload: params, - direction: 'toClient:send', - }); - } - } - - call( - api: string, - method: string, - fromPlugin: boolean, - params?: Object, - ): Promise { - return reportPluginFailures( - this.rawCall('execute', fromPlugin, { - api, - method, - params, - }).catch((err: Error) => { - // We only throw errors if the connection is still alive - // as connection-related ones aren't recoverable from - // user code. - if (this.connected.get()) { - // This is a special case where we a send failed because of - // a disconnect "mid-air". This can happen, for instance, - // when you pull the plug from a connected phone. We can - // still handle this gracefully. - if (err.toString().includes('Socket closed unexpectedly')) { - console.warn( - `Failed to call device due to unexpected disconnect: ${err}`, - ); - this.disconnect(); - return {}; - } - throw err; - } - // This effectively preserves the previous behavior - // of ignoring disconnection-related call failures. - return {}; - }), - `Call-${method}`, - api, - ); - } - - send(api: string, method: string, params?: Object): void { - if (!isProduction()) { - console.warn( - `${api}:${ - method || '' - } client.send() is deprecated. Please use call() instead so you can handle errors.`, - ); - } - return this.rawSend('execute', {api, method, params}); - } - - async supportsMethod(api: string, method: string): Promise { - const response = await this.rawCall<{ - isSupported: boolean; - }>('isMethodSupported', true, { - api, - method, - }); - return response.isSupported; - } } diff --git a/desktop/flipper-ui-core/src/__tests__/PluginContainer.node.tsx b/desktop/flipper-ui-core/src/__tests__/PluginContainer.node.tsx index 4aa894d9a..5a8d2f22d 100644 --- a/desktop/flipper-ui-core/src/__tests__/PluginContainer.node.tsx +++ b/desktop/flipper-ui-core/src/__tests__/PluginContainer.node.tsx @@ -171,7 +171,9 @@ test.skip('PluginContainer can render Sandy plugins', async () => { const {renderer, act, sendMessage, client, store} = await renderMockFlipperWithPlugin(definition); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); expect(renderer.baseElement).toMatchInlineSnapshot(` @@ -260,7 +262,9 @@ test.skip('PluginContainer can render Sandy plugins', async () => { ); }); - expect(client.rawSend).toBeCalledWith('deinit', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('deinit', { + plugin: 'TestPlugin', + }); expect(renderer.baseElement).toMatchInlineSnapshot(` @@ -326,7 +330,9 @@ test.skip('PluginContainer can render Sandy plugins', async () => { expect(pluginInstance.disconnectedStub).toBeCalledTimes(1); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(1); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); // disable act(() => { @@ -341,7 +347,9 @@ test.skip('PluginContainer can render Sandy plugins', async () => { expect(pluginInstance.disconnectedStub).toBeCalledTimes(2); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(2); - expect(client.rawSend).toBeCalledWith('deinit', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('deinit', { + plugin: 'TestPlugin', + }); // re-enable act(() => { @@ -365,7 +373,9 @@ test.skip('PluginContainer can render Sandy plugins', async () => { client.sandyPluginStates.get('TestPlugin')!.instanceApi; expect(newPluginInstance).not.toBe(pluginInstance); expect(newPluginInstance.connectedStub).toBeCalledTimes(1); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); expect(newPluginInstance.count.get()).toBe(0); }); @@ -401,8 +411,10 @@ test('PluginContainer triggers correct lifecycles for background plugin', async }, }); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); + ((client as any).rawSend as jest.Mock).mockClear(); // make sure the plugin gets connected const pluginInstance: ReturnType = client.sandyPluginStates.get(definition.id)!.instanceApi; @@ -423,8 +435,8 @@ test('PluginContainer triggers correct lifecycles for background plugin', async ); }); // bg plugin! - expect(client.rawSend).not.toBeCalled(); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).not.toBeCalled(); + ((client as any).rawSend as jest.Mock).mockClear(); expect(pluginInstance.connectedStub).toBeCalledTimes(1); expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(1); @@ -445,8 +457,8 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(1); - expect(client.rawSend).not.toBeCalled(); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).not.toBeCalled(); + ((client as any).rawSend as jest.Mock).mockClear(); // disable act(() => { @@ -461,8 +473,10 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(pluginInstance.disconnectedStub).toBeCalledTimes(1); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(2); - expect(client.rawSend).toBeCalledWith('deinit', {plugin: 'TestPlugin'}); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).toBeCalledWith('deinit', { + plugin: 'TestPlugin', + }); + ((client as any).rawSend as jest.Mock).mockClear(); // select something else act(() => { @@ -499,8 +513,10 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(newPluginInstance.disconnectedStub).toBeCalledTimes(0); expect(newPluginInstance.activatedStub).toBeCalledTimes(0); expect(newPluginInstance.deactivatedStub).toBeCalledTimes(0); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); + ((client as any).rawSend as jest.Mock).mockClear(); // select new plugin act(() => { @@ -517,8 +533,8 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(newPluginInstance.disconnectedStub).toBeCalledTimes(0); expect(newPluginInstance.activatedStub).toBeCalledTimes(1); expect(newPluginInstance.deactivatedStub).toBeCalledTimes(0); - expect(client.rawSend).not.toBeCalled(); - (client.rawSend as jest.Mock).mockClear(); + expect((client as any).rawSend).not.toBeCalled(); + ((client as any).rawSend as jest.Mock).mockClear(); }); test('PluginContainer + Sandy plugin supports deeplink', async () => { @@ -555,7 +571,9 @@ test('PluginContainer + Sandy plugin supports deeplink', async () => { definition, ); - expect(client.rawSend).toBeCalledWith('init', {plugin: 'TestPlugin'}); + expect((client as any).rawSend).toBeCalledWith('init', { + plugin: 'TestPlugin', + }); expect(linksSeen).toEqual([]); expect(renderer.baseElement).toMatchInlineSnapshot(` @@ -1242,7 +1260,7 @@ test('PluginContainer can render Sandy plugins for archived devices', async () = {archivedDevice: true}, ); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); expect(renderer.baseElement).toMatchInlineSnapshot(` @@ -1296,7 +1314,7 @@ test('PluginContainer can render Sandy plugins for archived devices', async () = ); }); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); expect(renderer.baseElement).toMatchInlineSnapshot(` @@ -1359,7 +1377,7 @@ test('PluginContainer can render Sandy plugins for archived devices', async () = expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(1); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); }); test('PluginContainer triggers correct lifecycles for background plugin', async () => { @@ -1397,7 +1415,7 @@ test('PluginContainer triggers correct lifecycles for background plugin', async }, }); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); // make sure the plugin gets connected const pluginInstance: ReturnType = client.sandyPluginStates.get(definition.id)!.instanceApi; @@ -1418,7 +1436,7 @@ test('PluginContainer triggers correct lifecycles for background plugin', async ); }); // bg plugin! - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); expect(pluginInstance.connectedStub).toBeCalledTimes(0); expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(1); @@ -1439,7 +1457,7 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(2); expect(pluginInstance.deactivatedStub).toBeCalledTimes(1); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); // select something else act(() => { @@ -1466,5 +1484,5 @@ test('PluginContainer triggers correct lifecycles for background plugin', async expect(pluginInstance.disconnectedStub).toBeCalledTimes(0); expect(pluginInstance.activatedStub).toBeCalledTimes(3); expect(pluginInstance.deactivatedStub).toBeCalledTimes(2); - expect(client.rawSend).not.toBeCalled(); + expect((client as any).rawSend).not.toBeCalled(); }); diff --git a/desktop/flipper-ui-core/src/__tests__/test-utils/MockFlipper.tsx b/desktop/flipper-ui-core/src/__tests__/test-utils/MockFlipper.tsx index 80ef54f68..21aed9a47 100644 --- a/desktop/flipper-ui-core/src/__tests__/test-utils/MockFlipper.tsx +++ b/desktop/flipper-ui-core/src/__tests__/test-utils/MockFlipper.tsx @@ -11,7 +11,7 @@ import {createStore} from 'redux'; import BaseDevice from '../../devices/BaseDevice'; import {createRootReducer} from '../../reducers'; import {Store} from '../../reducers/index'; -import Client, {ClientConnection} from '../../Client'; +import Client from '../../Client'; import { Logger, buildClientId, @@ -21,6 +21,7 @@ import { import {PluginDefinition} from '../../plugin'; import {pluginsInitialized, registerPlugins} from '../../reducers/plugins'; import {getLogger} from 'flipper-common'; +import {ClientConnection} from 'flipper-frontend-core'; import {initializeFlipperLibImplementation} from '../../utils/flipperLibImplementation'; import pluginManager from '../../dispatcher/pluginManager'; import {PluginDetails} from 'flipper-common'; @@ -197,6 +198,8 @@ export default class MockFlipper { this._logger, this._store, new Set(supportedPlugins), + // TODO: Remove after migration + // @ts-expect-error device, this.flipperServer, ); @@ -225,7 +228,7 @@ export default class MockFlipper { ); } }; - client.rawSend = jest.fn(); + (client as any).rawSend = jest.fn(); if (!device.isArchived) { await client.init(); } else { diff --git a/desktop/flipper-ui-core/src/deeplink.tsx b/desktop/flipper-ui-core/src/deeplink.tsx index cbe88eedd..67d273947 100644 --- a/desktop/flipper-ui-core/src/deeplink.tsx +++ b/desktop/flipper-ui-core/src/deeplink.tsx @@ -101,12 +101,16 @@ export async function handleDeeplink( const selectedClient = getAllClients(store.getState().connections).find( (c) => c.query.app === match[0] && + // TODO: Remove at the end of migration + // @ts-expect-error (selectedDevice == null || c.device === selectedDevice), ); store.dispatch( selectPlugin({ selectedAppId: selectedClient?.id, + // TODO: Remove at the end of migration + // @ts-expect-error selectedDevice: selectedClient ? selectedClient.device : selectedDevice, selectedPlugin: match[1], deepLinkPayload, diff --git a/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx b/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx index 6a5b4fd73..c0d6ea8c3 100644 --- a/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx +++ b/desktop/flipper-ui-core/src/dispatcher/flipperServer.tsx @@ -300,6 +300,8 @@ export async function handleClientConnected( logger, store, undefined, + // TODO: Remove at the end of migration + // @ts-expect-error device, server, ); diff --git a/desktop/flipper-ui-core/src/dispatcher/handleOpenPluginDeeplink.tsx b/desktop/flipper-ui-core/src/dispatcher/handleOpenPluginDeeplink.tsx index 6a5b9bc6c..63d1d3804 100644 --- a/desktop/flipper-ui-core/src/dispatcher/handleOpenPluginDeeplink.tsx +++ b/desktop/flipper-ui-core/src/dispatcher/handleOpenPluginDeeplink.tsx @@ -122,6 +122,8 @@ export async function handleOpenPluginDeeplink( const client: Client | undefined = isDevicePlugin ? undefined : (deviceOrClient as Client); + // TODO: Remove at the end of migration + // @ts-expect-error const device: BaseDevice = isDevicePlugin ? (deviceOrClient as BaseDevice) : (deviceOrClient as Client).device; @@ -507,6 +509,8 @@ async function selectDevicesAndClient( : c.plugins.has(params.pluginId), ) .filter((c) => c.connected.get()) + // TODO: Remove at the end of migration + // @ts-expect-error .filter((c) => availableDevices.includes(c.device)); if (validClients.length === 1) { diff --git a/desktop/flipper-ui-core/src/reducers/connections.tsx b/desktop/flipper-ui-core/src/reducers/connections.tsx index e8952684f..774209064 100644 --- a/desktop/flipper-ui-core/src/reducers/connections.tsx +++ b/desktop/flipper-ui-core/src/reducers/connections.tsx @@ -243,11 +243,15 @@ export default (state: State = INITAL_STATE, action: Actions): State => { selectedAppId = getAllClients(state).find( (c) => + // TODO: Remove after migration + // @ts-expect-error c.device === payload && c.query.app === state.userPreferredApp, )?.id ?? null; // nothing found, try first app if any if (!selectedAppId) { selectedAppId = + // TODO: Remove after migration + // @ts-expect-error getAllClients(state).find((c) => c.device === payload)?.id ?? null; } } @@ -280,7 +284,11 @@ export default (state: State = INITAL_STATE, action: Actions): State => { return { ...state, staticView: null, + // TODO: Remove after migration + // @ts-expect-error selectedDevice: device, + // TODO: Remove after migration + // @ts-expect-error userPreferredDevice: canBeDefaultDevice(device) ? device.title : state.userPreferredDevice, @@ -337,6 +345,8 @@ export default (state: State = INITAL_STATE, action: Actions): State => { return { ...state, selectedAppId: payload, + // TODO: Remove after migration + // @ts-expect-error selectedDevice: client.device, userPreferredDevice: client.device.title, userPreferredApp: client.query.app, diff --git a/desktop/flipper-ui-core/src/sandy-chrome/notification/Notification.tsx b/desktop/flipper-ui-core/src/sandy-chrome/notification/Notification.tsx index 3454fc8f1..03ced0517 100644 --- a/desktop/flipper-ui-core/src/sandy-chrome/notification/Notification.tsx +++ b/desktop/flipper-ui-core/src/sandy-chrome/notification/Notification.tsx @@ -311,6 +311,8 @@ export function openNotification(store: Store, noti: PluginNotificationOrig) { selectPlugin({ selectedPlugin: noti.pluginId, selectedAppId: client.id, + // TODO: Will be fixed later in the stack + // @ts-expect-error selectedDevice: client.device, deepLinkPayload: noti.notification.action, }), diff --git a/desktop/flipper-ui-core/src/selectors/connections.tsx b/desktop/flipper-ui-core/src/selectors/connections.tsx index 11c023e22..aa75b253b 100644 --- a/desktop/flipper-ui-core/src/selectors/connections.tsx +++ b/desktop/flipper-ui-core/src/selectors/connections.tsx @@ -63,7 +63,8 @@ export const getActiveDevice = createSelector( } // if there is an active app, use device owning the app if (client) { - return client.device; + // TODO: Will be fixed later in the stack + return client.device as any; } return selectedDevice; }, diff --git a/desktop/flipper-ui-core/src/utils/__tests__/exportData.node.tsx b/desktop/flipper-ui-core/src/utils/__tests__/exportData.node.tsx index f5d064113..d16cbaebd 100644 --- a/desktop/flipper-ui-core/src/utils/__tests__/exportData.node.tsx +++ b/desktop/flipper-ui-core/src/utils/__tests__/exportData.node.tsx @@ -733,6 +733,8 @@ test('test determinePluginsToProcess for mutilple clients having plugins present logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -748,6 +750,8 @@ test('test determinePluginsToProcess for mutilple clients having plugins present logger, mockStore, new Set(['TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -763,6 +767,8 @@ test('test determinePluginsToProcess for mutilple clients having plugins present logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -823,6 +829,8 @@ test('test determinePluginsToProcess for no selected plugin present in any clien logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -838,6 +846,8 @@ test('test determinePluginsToProcess for no selected plugin present in any clien logger, mockStore, new Set(['TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -881,6 +891,8 @@ test('test determinePluginsToProcess for multiple clients on same device', async logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -896,6 +908,8 @@ test('test determinePluginsToProcess for multiple clients on same device', async logger, mockStore, new Set(['TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -944,6 +958,8 @@ test('test determinePluginsToProcess for multiple clients on different device', logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -959,6 +975,8 @@ test('test determinePluginsToProcess for multiple clients on different device', logger, mockStore, new Set(['TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -974,6 +992,8 @@ test('test determinePluginsToProcess for multiple clients on different device', logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -989,6 +1009,8 @@ test('test determinePluginsToProcess for multiple clients on different device', logger, mockStore, new Set(['TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error device1, flipperServer, ); @@ -1061,6 +1083,8 @@ test('test determinePluginsToProcess to ignore archived clients', async () => { logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error archivedDevice, flipperServer, ); @@ -1076,6 +1100,8 @@ test('test determinePluginsToProcess to ignore archived clients', async () => { logger, mockStore, new Set(['TestPlugin', 'TestDevicePlugin']), + // TODO: Remove at the end of migration + // @ts-expect-error archivedDevice, flipperServer, ); diff --git a/desktop/flipper-ui-core/src/utils/exportData.tsx b/desktop/flipper-ui-core/src/utils/exportData.tsx index 0d8558463..31aedb4f3 100644 --- a/desktop/flipper-ui-core/src/utils/exportData.tsx +++ b/desktop/flipper-ui-core/src/utils/exportData.tsx @@ -18,7 +18,7 @@ import {getAppVersion} from './info'; import {pluginKey} from '../utils/pluginKey'; import {DevicePluginMap, ClientPluginMap} from '../plugin'; import {default as BaseDevice} from '../devices/BaseDevice'; -import {default as ArchivedDevice} from '../devices/ArchivedDevice'; +import {ArchivedDevice} from 'flipper-frontend-core'; import {v4 as uuidv4} from 'uuid'; import {tryCatchReportPlatformFailures} from 'flipper-common'; import {TestIdler} from './Idler'; @@ -512,7 +512,11 @@ export const exportStoreToFile = ( ); }; -export function importDataToStore(source: string, data: string, store: Store) { +export async function importDataToStore( + source: string, + data: string, + store: Store, +) { getLogger().track('usage', IMPORT_FLIPPER_TRACE_EVENT); const json: ExportType = JSON.parse(data); const {device, clients, deviceScreenshot} = json; @@ -536,19 +540,22 @@ export function importDataToStore(source: string, data: string, store: Store) { ); store.dispatch({ type: 'REGISTER_DEVICE', + // TODO: Remove at the end of migration + // @ts-expect-error payload: archivedDevice, }); store.dispatch({ type: 'SELECT_DEVICE', + // TODO: Remove at the end of migration + // @ts-expect-error payload: archivedDevice, }); - clients.forEach((client: {id: string; query: ClientQuery}) => { - const sandyPluginStates = json.pluginStates2[client.id] || {}; - const clientPlugins = new Set(Object.keys(sandyPluginStates)); - store.dispatch({ - type: 'NEW_CLIENT', - payload: new Client( + await Promise.all( + clients.map(async (client: {id: string; query: ClientQuery}) => { + const sandyPluginStates = json.pluginStates2[client.id] || {}; + const clientPlugins = new Set(Object.keys(sandyPluginStates)); + const clientInstance = await new Client( client.id, client.query, null, @@ -557,9 +564,13 @@ export function importDataToStore(source: string, data: string, store: Store) { clientPlugins, archivedDevice, getRenderHostInstance().flipperServer, - ).initFromImport(sandyPluginStates), - }); - }); + ).initFromImport(sandyPluginStates); + store.dispatch({ + type: 'NEW_CLIENT', + payload: clientInstance, + }); + }), + ); } export const importFileToStore = async (file: string, store: Store) => { diff --git a/desktop/flipper-ui-core/tsconfig.json b/desktop/flipper-ui-core/tsconfig.json index 1882c0c7d..5e6c32944 100644 --- a/desktop/flipper-ui-core/tsconfig.json +++ b/desktop/flipper-ui-core/tsconfig.json @@ -12,6 +12,9 @@ { "path": "../flipper-common" }, + { + "path": "../flipper-frontend-core" + }, { "path": "../flipper-plugin" }, diff --git a/desktop/jest.config.js b/desktop/jest.config.js index 630cdb374..d30a43c44 100644 --- a/desktop/jest.config.js +++ b/desktop/jest.config.js @@ -17,7 +17,8 @@ module.exports = { moduleNameMapper: { '^flipper$': '/app/src', '^flipper-plugin$': '/flipper-plugin/src', - '^flipper-(server-core|ui-core|common)$': '/flipper-$1/src', + '^flipper-(server-core|ui-core|frontend-core|common)$': + '/flipper-$1/src', '^flipper-(pkg|pkg-lib|doctor|test-utils)$': '/$1/src', }, clearMocks: true, diff --git a/desktop/plugins/public/layout/index.tsx b/desktop/plugins/public/layout/index.tsx index a76cef0ab..703c6f9b4 100644 --- a/desktop/plugins/public/layout/index.tsx +++ b/desktop/plugins/public/layout/index.tsx @@ -258,6 +258,7 @@ export default class LayoutPlugin extends FlipperPlugin< if (this.props.isArchivedDevice) { Promise.resolve(this.device) .then((d) => { + // @ts-expect-error const handle = (d as ArchivedDevice).getArchivedScreenshotHandle(); if (!handle) { throw new Error('No screenshot attached.'); diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 6943cbf4d..04c2699f6 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -4035,14 +4035,6 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -aggregate-error@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-4.0.0.tgz#83dbdb53a0d500721281d22e19eee9bc352a89cd" - integrity sha512-8DGp7zUt1E9k0NE2q4jlXHk+V3ORErmwolEdRz9iV+LKJ40WhMHh92cxAvhqV2I+zEn/gotIoqoMs0NjF3xofg== - dependencies: - clean-stack "^4.0.0" - indent-string "^5.0.0" - ajv-errors@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -5340,13 +5332,6 @@ clean-stack@^3.0.0, clean-stack@^3.0.1: dependencies: escape-string-regexp "4.0.0" -clean-stack@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-4.1.0.tgz#5ce5a2fd19a12aecdce8570daefddb7ac94b6b4e" - integrity sha512-dxXQYI7mfQVcaF12s6sjNFoZ6ZPDQuBBLp3QJ5156k9EvUFClUoZ11fo8HnLQO241DDVntHEug8MOuFO5PSfRg== - dependencies: - escape-string-regexp "5.0.0" - cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" @@ -6662,11 +6647,6 @@ escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" - integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -8211,11 +8191,6 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -indent-string@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" - integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -11256,13 +11231,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-map@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-5.3.0.tgz#2204823bc9f37f17ddc9e7f446293c4530b8a4cf" - integrity sha512-SRbIQFoLYNezHkqZslqeg963HYUtqOrfMCxjNrFOpJ19WTYuq26rQoOXeX8QQiMLUlLqdYV/7PuDsdYJ7hLE1w== - dependencies: - aggregate-error "^4.0.0" - p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"