diff --git a/desktop/app/src/chrome/JSEmulatorLauncherSheet.tsx b/desktop/app/src/chrome/JSEmulatorLauncherSheet.tsx index c266fc420..f6d1cee4c 100644 --- a/desktop/app/src/chrome/JSEmulatorLauncherSheet.tsx +++ b/desktop/app/src/chrome/JSEmulatorLauncherSheet.tsx @@ -20,7 +20,7 @@ import { import React, {Component} from 'react'; import {connect} from 'react-redux'; import {State as Store} from '../reducers'; -import {launchJsEmulator} from '../utils/js-client/serverUtils'; +import {launchJsEmulator} from '../utils/js-client-server-utils/serverUtils'; import {updateSettings, Action} from '../reducers/settings'; import {Settings} from '../reducers/settings'; diff --git a/desktop/app/src/server.tsx b/desktop/app/src/server.tsx index a539c0274..90431bf08 100644 --- a/desktop/app/src/server.tsx +++ b/desktop/app/src/server.tsx @@ -24,12 +24,12 @@ import tls from 'tls'; import net, {Socket} from 'net'; import {Responder, Payload, ReactiveSocket} from 'rsocket-types'; import GK from './fb-stubs/GK'; -import {initJsEmulatorIPC} from './utils/js-client/serverUtils'; +import {initJsEmulatorIPC} from './utils/js-client-server-utils/serverUtils'; import {buildClientId} from './utils/clientUtils'; import {Single} from 'rsocket-flowable'; import WebSocket from 'ws'; import JSDevice from './devices/JSDevice'; -import {WebsocketClientFlipperConnection} from './utils/js-client/websocketClientFlipperConnection'; +import {WebsocketClientFlipperConnection} from './utils/js-client-server-utils/websocketClientFlipperConnection'; import querystring from 'querystring'; import {IncomingMessage} from 'http'; import ws from 'ws'; @@ -161,7 +161,8 @@ class Server extends EventEmitter { }) => { return ( info.origin.startsWith('chrome-extension://') || - info.origin.startsWith('localhost:') + info.origin.startsWith('localhost:') || + info.origin.startsWith('http://localhost:') ); }, }); @@ -240,8 +241,8 @@ class Server extends EventEmitter { cleanup(); }); }); - wss.on('error', (_ws: WebSocket) => { - console.error('error from wss'); + wss.on('error', (_ws: WebSocket, e: any) => { + console.error('error from wss' + e); }); } diff --git a/desktop/app/src/utils/js-client/serverUtils.tsx b/desktop/app/src/utils/js-client-server-utils/serverUtils.tsx similarity index 100% rename from desktop/app/src/utils/js-client/serverUtils.tsx rename to desktop/app/src/utils/js-client-server-utils/serverUtils.tsx diff --git a/desktop/app/src/utils/js-client/websocketClientFlipperConnection.tsx b/desktop/app/src/utils/js-client-server-utils/websocketClientFlipperConnection.tsx similarity index 100% rename from desktop/app/src/utils/js-client/websocketClientFlipperConnection.tsx rename to desktop/app/src/utils/js-client-server-utils/websocketClientFlipperConnection.tsx diff --git a/desktop/app/src/utils/js-client/api.js b/desktop/app/src/utils/js-client/api.js deleted file mode 100644 index 7fbe4947a..000000000 --- a/desktop/app/src/utils/js-client/api.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -export type FlipperPluginID = string; - -export type FlipperMethodID = string; - -export class FlipperBridge { - registerPlugins: (plugins: Array) => void; - - start: (appName: string) => void; - - stop: () => void; - - sendData: ( - plugin: FlipperPluginID, - method: FlipperMethodID, - data: any, - ) => void; - - subscribe: ( - plugin: FlipperPluginID, - method: FlipperMethodID, - handler: (any) => void, - ) => void; - - isAvailable: () => boolean; -} - -export class FlipperResponder { - pluginId: FlipperPluginID; - methodId: FlipperMethodID; - _bridge: FlipperBridge; - - constructor( - pluginId: FlipperPluginID, - methodId: FlipperMethodID, - bridge: FlipperBridge, - ) { - this.pluginId = pluginId; - this.methodId = methodId; - this._bridge = bridge; - } - - success(response: any) {} - - error(response: any) {} -} - -export type FlipperReceiver = ( - params: T, - responder: FlipperResponder, -) => void; - -export class FlipperConnection { - pluginId: FlipperPluginID; - _bridge: FlipperBridge; - - constructor(pluginId: FlipperPluginID, bridge: FlipperBridge) { - this.pluginId = pluginId; - this._bridge = bridge; - } - - send(method: FlipperMethodID, data: any) { - this._bridge.sendData(this.pluginId, method, data); - } - - receive(method: FlipperMethodID, receiver: FlipperReceiver<*>) { - this._bridge.subscribe(this.pluginId, method, (data) => { - receiver(data, new FlipperResponder(this.pluginId, method, this._bridge)); - }); - } -} - -export class FlipperPlugin { - id: FlipperPluginID; - _connection: ?FlipperConnection; - - onConnect(connection: FlipperConnection) { - this._connection = connection; - } -} - -export class FlipperClient { - _bridge: FlipperBridge; - plugins: Map = new Map(); - - constructor(bridge: FlipperBridge) { - this._bridge = bridge; - } - - addPlugin(plugin: FlipperPlugin) { - plugin.onConnect(new FlipperConnection(plugin.id, this._bridge)); - this.plugins.set(plugin.id, plugin); - } - - getPlugin(id: FlipperPluginID): ?FlipperPlugin { - return this.plugins.get(id); - } - - start(appName: string) { - this._bridge.registerPlugins([...this.plugins.keys()]); - this._bridge.start(appName); - } - - stop() { - this._bridge.stop(); - } -} diff --git a/desktop/app/src/utils/js-client/example.js b/desktop/app/src/utils/js-client/example.js deleted file mode 100644 index 356a59660..000000000 --- a/desktop/app/src/utils/js-client/example.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import {FlipperClient} from './api'; -import {newWebviewClient} from './webviewImpl'; -import {AnalyticsLoggingFlipperPlugin} from './plugins/analyticsLogging'; -import {FuryPlugin} from './plugins/fury'; - -class FlipperManager { - flipperClient: FlipperClient; - analyticsPlugin: AnalyticsLoggingFlipperPlugin; - furyPlugin: FuryPlugin; - - constructor() { - this.flipperClient = newWebviewClient(); - this.analyticsPlugin = new AnalyticsLoggingFlipperPlugin(); - this.furyPlugin = new FuryPlugin(); - this.flipperClient.addPlugin(this.analyticsPlugin); - this.flipperClient.addPlugin(this.furyPlugin); - this.flipperClient.start('Example JS App'); - } -} - -let flipperManager: ?FlipperManager; - -export function init() { - if (!flipperManager) { - flipperManager = new FlipperManager(); - } -} - -export function flipper(): ?FlipperManager { - return flipperManager; -} diff --git a/desktop/app/src/utils/js-client/package.json b/desktop/app/src/utils/js-client/package.json deleted file mode 100644 index 854d77cdb..000000000 --- a/desktop/app/src/utils/js-client/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "flipper-js-client", - "version": "0.46.0", - "private": true, - "main": "index.js", - "license": "MIT", - "title": "Flipper JS Client", - "icon": "apps", - "bugs": { - "email": "timurvaliev@fb.com" - }, - "dependencies": { - "rsocket-flowable": "^0.0.14", - "rsocket-types": "^0.0.16", - "ws": "^7.2.3" - } -} diff --git a/desktop/app/src/utils/js-client/plugins/analyticsLogging.js b/desktop/app/src/utils/js-client/plugins/analyticsLogging.js deleted file mode 100644 index 315d9965c..000000000 --- a/desktop/app/src/utils/js-client/plugins/analyticsLogging.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import {FlipperPlugin} from '../api'; - -import type {FlipperPluginID} from '../api'; - -type EventId = string; - -export type AnalyticsEvent = { - id: EventId, - module: string, - name: string, - time: number, - filter: ?string, - highpri: ?boolean, - extras: any, -}; - -export class AnalyticsLoggingFlipperPlugin extends FlipperPlugin { - id: FlipperPluginID = 'AnalyticsLogging'; - - sendEvent(event: AnalyticsEvent) { - this._connection && this._connection.send('reportEvent', event); - } -} diff --git a/desktop/app/src/utils/js-client/plugins/fury.js b/desktop/app/src/utils/js-client/plugins/fury.js deleted file mode 100644 index 7665262b1..000000000 --- a/desktop/app/src/utils/js-client/plugins/fury.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -import {FlipperPlugin, FlipperResponder, FlipperConnection} from '../api'; - -import type {FlipperPluginID} from '../api'; - -type EventId = string; - -type EventType = number; -type ThreadID = number; -type SeqID = number; - -type StackTraceElement = { - className: string, - methodName: string, - fileName: string, - lineNumber: number, -}; - -type FuryTaskEvent = { - id: EventId, - time: number, - eventType: EventType, - callStack: StackTraceElement[], - extras: any, - tag: string, - parentTid: ThreadID, - currentTid: ThreadID, - parentSeqId: SeqID, - currentSeqId: SeqID, - isDirect: boolean, - isPoint: boolean, - isOnActivated: boolean, -}; - -export type ReqContext = { - tag: string, - parentSeqId: SeqID, - currentSeqId: SeqID, - isDirect: boolean, - isPoint: boolean, -}; - -const structuredTraceFun = (error, structuredStackTrace) => { - return structuredStackTrace; -}; - -function getStackTrace(): CallSite[] { - const oldPrep = Error.prepareStackTrace; - Error.prepareStackTrace = structuredTraceFun; - const error = {}; - Error.captureStackTrace(error, getStackTrace); - const stack = error.stack; - Error.prepareStackTrace = oldPrep; - return stack; -} - -export class FuryPlugin extends FlipperPlugin { - id: FlipperPluginID = 'Fury'; - - onConnect(connection: FlipperConnection) { - super.onConnect(connection); - connection.receive( - 'toggleRecording', - (data: any, responder: FlipperResponder) => { - window.console.log(data); - }, - ); - } - - processEvent(reqContext: ReqContext, isOnActivated: boolean) { - const stack = getStackTrace(); - const eventType = reqContext.isPoint ? 2 : isOnActivated ? 0 : 1; - const event: FuryTaskEvent = { - id: reqContext.currentSeqId + '/' + eventType, - time: new Date().getTime(), - eventType: eventType, - callStack: stack.map((frame) => { - return { - className: frame.getTypeName() || '', - methodName: frame.getFunctionName() || '', - fileName: frame.getFileName() || '', - lineNumber: frame.getLineNumber() || 0, - }; - }), - extras: {}, - tag: reqContext.tag, - parentTid: -1, - currentTid: -1, - parentSeqId: reqContext.parentSeqId, - currentSeqId: reqContext.currentSeqId, - isDirect: reqContext.isDirect, - isPoint: reqContext.isPoint, - isOnActivated: isOnActivated, - }; - this._connection && this._connection.send('reportEvent', event); - } -} diff --git a/desktop/app/src/utils/js-client/webviewImpl.js b/desktop/app/src/utils/js-client/webviewImpl.js deleted file mode 100644 index 152dd1bf2..000000000 --- a/desktop/app/src/utils/js-client/webviewImpl.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import {FlipperClient, FlipperBridge} from './api'; - -import type {FlipperPluginID, FlipperMethodID} from './api'; - -class FlipperWebviewBridgeImpl extends FlipperBridge { - _subscriptions: Map void> = new Map(); - - registerPlugins = (plugins: Array) => { - window.FlipperWebviewBridge && - window.FlipperWebviewBridge.registerPlugins(plugins); - }; - - start = (appName: string) => { - window.FlipperWebviewBridge && window.FlipperWebviewBridge.start(appName); - }; - - stop = () => { - window.FlipperWebviewBridge && window.FlipperWebviewBridge.stop(); - }; - - sendData = (plugin: FlipperPluginID, method: FlipperMethodID, data: any) => { - window.FlipperWebviewBridge && - window.FlipperWebviewBridge.sendFlipperObject( - plugin, - method, - JSON.stringify(data), - ); - }; - - subscribe = ( - plugin: FlipperPluginID, - method: FlipperMethodID, - handler: (any) => void, - ) => { - this._subscriptions.set(plugin + method, handler); - }; - - isAvailable = () => { - return window.FlipperWebviewBridge != null; - }; - - receive(plugin: FlipperPluginID, method: FlipperMethodID, data: string) { - const handler = this._subscriptions.get(plugin + method); - handler && handler(JSON.parse(data)); - } -} - -export function newWebviewClient(): FlipperClient { - const bridge = new FlipperWebviewBridgeImpl(); - window.flipper = { - FlipperWebviewMessageReceiver: bridge, - }; - return new FlipperClient(bridge); -} diff --git a/desktop/app/src/utils/js-client/yarn.lock b/desktop/app/src/utils/js-client/yarn.lock deleted file mode 100644 index 5a17c5964..000000000 --- a/desktop/app/src/utils/js-client/yarn.lock +++ /dev/null @@ -1,150 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - -buffer@^5.0.6: - version "5.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -core-js@^2.4.1: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= - dependencies: - iconv-lite "~0.4.13" - -fbjs-css-vars@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" - integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== - -fbjs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz#52c215e0883a3c86af2a7a776ed51525ae8e0a5a" - integrity sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA== - dependencies: - core-js "^2.4.1" - fbjs-css-vars "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - -iconv-lite@~0.4.13: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - -rsocket-flowable@^0.0.14: - version "0.0.14" - resolved "https://registry.yarnpkg.com/rsocket-flowable/-/rsocket-flowable-0.0.14.tgz#5195dbd2972a98afe4a4ee082904fbc5890bc630" - integrity sha512-vK85yDj0DRpoTV1jQZF0JmSuQz4qj2DHMyV744I9h/8AP5jVJhuN1D+ArKQvP0VWXjFoRK23ObVMnoSdSkk4pg== - dependencies: - fbjs "^1.0.0" - -rsocket-types@^0.0.16: - version "0.0.16" - resolved "https://registry.yarnpkg.com/rsocket-types/-/rsocket-types-0.0.16.tgz#2113dcf8e25478d6764f1e3e84ad4a97d16a6fde" - integrity sha512-zOJ2u5bgooj8QewqoIoaeEn1FHDZSyHp7VuDSiEJAAjTTQpYyEqKpLTvqi+tazRCBOTfulMBijootTI18VVeIg== - dependencies: - buffer "^5.0.6" - fbjs "^1.0.0" - rsocket-flowable "^0.0.14" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -ua-parser-js@^0.7.18: - version "0.7.21" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" - integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== - -whatwg-fetch@>=0.10.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== - -ws@^7.2.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== diff --git a/desktop/package.json b/desktop/package.json index 1089a91b6..05a78b414 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -16,7 +16,6 @@ "workspaces": { "packages": [ "app", - "app/src/utils/js-client", "babel-transformer", "doctor", "headless", diff --git a/flipper-js-client-sdk/.gitignore b/flipper-js-client-sdk/.gitignore new file mode 100644 index 000000000..20210ae4e --- /dev/null +++ b/flipper-js-client-sdk/.gitignore @@ -0,0 +1,4 @@ +lib/ +node_modules/ +*.tsbuildinfo +/coverage diff --git a/flipper-js-client-sdk/LICENSE b/flipper-js-client-sdk/LICENSE new file mode 100644 index 000000000..b96dcb048 --- /dev/null +++ b/flipper-js-client-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/flipper-js-client-sdk/README.md b/flipper-js-client-sdk/README.md new file mode 100644 index 000000000..3a26a8922 --- /dev/null +++ b/flipper-js-client-sdk/README.md @@ -0,0 +1,34 @@ +# flipper-sdk-api + +SDK to build Flipper clients for JS based apps + +## Installation + +`yarn add flipper-client-sdk` + +## Usage + +## Example + +```TypeScript +class SeaMammalPlugin extends AbsctractFlipperPlugin { + getId(): string { + return 'sea-mammals'; + } + + runInBackground(): boolean { + return true; + } + + newRow(row: {id: string, url: string, title: string}) { + this.connection?.send("newRow", row) + } +} + +const flipperClient = newWebviewClient(); +cosnt plugin = new SeaMammalPlugin(); +flipperClient.addPlugin(); +flipperClient.start('Example JS App'); +plugin.newRow({id: '1', title: 'Dolphin', url: 'example.com'}) + +``` diff --git a/flipper-js-client-sdk/package.json b/flipper-js-client-sdk/package.json new file mode 100644 index 000000000..62b2f8ef1 --- /dev/null +++ b/flipper-js-client-sdk/package.json @@ -0,0 +1,28 @@ +{ + "name": "flipper-client-sdk", + "version": "0.0.1", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "title": "Flipper SDK API", + "scripts": { + "reset": "rimraf lib *.tsbuildinfo", + "build": "tsc -b" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/facebook/flipper.git", + "baseUrl": "https://github.com/facebook/flipper/tree/master/flipper-js-client-sdk" + }, + "keywords": [ + "flipper" + ], + "author": { + "name": "Facebook Inc" + }, + "license": "MIT", + "licenseFilename": "LICENSE", + "readmeFilename": "README.md", + "devDependencies": { + "typescript": "^3.9.2" + } +} diff --git a/flipper-js-client-sdk/src/api.ts b/flipper-js-client-sdk/src/api.ts new file mode 100644 index 000000000..2b3e5ac2a --- /dev/null +++ b/flipper-js-client-sdk/src/api.ts @@ -0,0 +1,147 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +export type FlipperPluginID = string; + +export type FlipperMethodID = string; + +export class FlipperResponder { + pluginId: FlipperPluginID; + methodId: FlipperMethodID; + private _client: FlipperClient; + + constructor( + pluginId: FlipperPluginID, + methodId: FlipperMethodID, + client: FlipperClient + ) { + this.pluginId = pluginId; + this.methodId = methodId; + this._client = client; + } + + success(_response: any) {} + + error(_response: any) {} +} + +export type FlipperReceiver = ( + params: T, + responder: FlipperResponder, +) => void; + +export class FlipperConnection { + pluginId: FlipperPluginID; + private client: FlipperClient; + + constructor(pluginId: FlipperPluginID, client: FlipperClient) { + this.pluginId = pluginId; + this.client = client; + } + + send(method: FlipperMethodID, data: any) { + this.client.sendData(this.pluginId, method, data); + } + + receive(method: FlipperMethodID, receiver: FlipperReceiver) { + this.client.subscribe(this.pluginId, method, (data: T) => { + receiver(data, new FlipperResponder(this.pluginId, method, this.client)); + }); + } +} + +export interface FlipperPlugin { + /** + * @return The id of this plugin. This is the namespace which Flipper desktop plugins will call + * methods on to route them to your plugin. This should match the id specified in your React + * plugin. + */ + getId(): string; + + /** + * Called when a connection has been established. The connection passed to this method is valid + * until {@link FlipperPlugin#onDisconnect()} is called. + */ + onConnect(connection: FlipperConnection): void; + + /** + * Called when the connection passed to `FlipperPlugin#onConnect(FlipperConnection)` is no + * longer valid. Do not try to use the connection in or after this method has been called. + */ + onDisconnect(): void; + + /** + * Returns true if the plugin is meant to be run in background too, otherwise it returns false. + */ + runInBackground(): boolean; +} + +export abstract class AbstractFlipperPlugin implements FlipperPlugin{ + protected connection: FlipperConnection | null | undefined; + + onConnect(connection: FlipperConnection): void { + this.connection = connection; + } + onDisconnect(): void { + this.connection = null; + } + + abstract getId(): string; + abstract runInBackground(): boolean; + +} + +export abstract class FlipperClient { + _isConnected: boolean = false; + plugins: Map = new Map(); + + addPlugin(plugin: FlipperPlugin) { + if (this._isConnected) { + plugin.onConnect(new FlipperConnection(plugin.getId(), this)); + } + this.plugins.set(plugin.getId(), plugin); + } + + getPlugin(id: FlipperPluginID): FlipperPlugin | undefined { + return this.plugins.get(id); + } + + onConnect() { + if (this._isConnected) { + return; + } + this._isConnected = true; + Array.from(this.plugins.values()).map((plugin) => + plugin.onConnect(new FlipperConnection(plugin.getId(), this)), + ); + } + + onDisconnect() { + this._isConnected = false; + Array.from(this.plugins.values()).map((plugin) => plugin.onDisconnect()); + } + + abstract start: (appName: string) => void; + + abstract stop: () => void; + + abstract sendData: ( + plugin: FlipperPluginID, + method: FlipperMethodID, + data: any, + ) => void; + + abstract subscribe: ( + plugin: FlipperPluginID, + method: FlipperMethodID, + handler: (message: T) => void, + ) => void; + + abstract isAvailable: () => boolean; +} diff --git a/flipper-js-client-sdk/src/example.ts b/flipper-js-client-sdk/src/example.ts new file mode 100644 index 000000000..7991077c1 --- /dev/null +++ b/flipper-js-client-sdk/src/example.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {FlipperClient, AbstractFlipperPlugin} from './api'; +import {newWebviewClient} from './webviewImpl'; + +class SeaMammalPlugin extends AbstractFlipperPlugin { + getId(): string { + return 'sea-mammals'; + } + + runInBackground(): boolean { + return true; + } + + newRow(row: {id: string, url: string, title: string}) { + this.connection?.send("newRow", row) +} + +} + +class FlipperManager { + flipperClient: FlipperClient; + seaMammalPlugin: SeaMammalPlugin; + + constructor() { + this.flipperClient = newWebviewClient(); + this.seaMammalPlugin = new SeaMammalPlugin(); + this.flipperClient.addPlugin(this.seaMammalPlugin); + this.flipperClient.start('Example JS App'); + } +} + +let flipperManager: FlipperManager | undefined; + +export function init() { + if (!flipperManager) { + flipperManager = new FlipperManager(); + } +} + +export function flipper(): FlipperManager | undefined { + return flipperManager; +} diff --git a/flipper-js-client-sdk/src/index.ts b/flipper-js-client-sdk/src/index.ts new file mode 100644 index 000000000..c47ca46c4 --- /dev/null +++ b/flipper-js-client-sdk/src/index.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +export * from './api'; diff --git a/flipper-js-client-sdk/src/webviewImpl.ts b/flipper-js-client-sdk/src/webviewImpl.ts new file mode 100644 index 000000000..3c7d29b21 --- /dev/null +++ b/flipper-js-client-sdk/src/webviewImpl.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {FlipperClient} from './api'; + +import type {FlipperPluginID, FlipperMethodID} from './api'; + +class FlipperWebviewClient extends FlipperClient { + _subscriptions: Map void> = new Map(); + _client: FlipperClient | null = null; + + start = (appName: string) => { + const bridge = (window as any).FlipperWebviewBridge; + bridge?.registerPlugins(this.plugins); + bridge?.start(appName); + }; + + stop = () => { + const bridge = (window as any).FlipperWebviewBridge; + bridge?.FlipperWebviewBridge.stop(); + }; + + sendData = (plugin: FlipperPluginID, method: FlipperMethodID, data: any) => { + const bridge = (window as any).FlipperWebviewBridge; + bridge && bridge.sendFlipperObject(plugin, method, JSON.stringify(data)); + }; + + subscribe = ( + plugin: FlipperPluginID, + method: FlipperMethodID, + handler: (msg: any) => void, + ) => { + this._subscriptions.set(plugin + method, handler); + }; + + isAvailable = () => { + return (window as any).FlipperWebviewBridge != null; + }; + + receive(plugin: FlipperPluginID, method: FlipperMethodID, data: string) { + const handler = this._subscriptions.get(plugin + method); + handler && handler(JSON.parse(data)); + } + + setClient(client: FlipperClient) { + this._client = client; + } +} + +export function newWebviewClient(): FlipperClient { + return new FlipperWebviewClient(); +} diff --git a/flipper-js-client-sdk/tsconfig.json b/flipper-js-client-sdk/tsconfig.json new file mode 100644 index 000000000..f43309d08 --- /dev/null +++ b/flipper-js-client-sdk/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + "esModuleInterop": true, + "target": "ES2017", + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "declaration": true, + "moduleResolution": "node", + "skipLibCheck": true, + "strict": true, + "downlevelIteration": true, + "module": "commonjs", + "lib": [ + "es7", + "dom", + "es2017" + ], + "composite": true, + "baseUrl": ".", + "allowJs": true + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules", + "**/__tests__/*" + ] +} diff --git a/flipper-js-client-sdk/yarn.lock b/flipper-js-client-sdk/yarn.lock new file mode 100644 index 000000000..9362a6558 --- /dev/null +++ b/flipper-js-client-sdk/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +typescript@^3.9.2: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==