update js-client api (migrate to TS)
Summary: JS/TS api: - migrate to TS - some refactoring (get rid of bridge, make client abstract) Implementation isn't full yet, things to be implemented: - let plugins connect on init command from Flipper - implement Responder Further plans: - make fully compatible with react-native api without breaking changes Reviewed By: mweststrate Differential Revision: D21839377 fbshipit-source-id: 9e9fe4ad01632f958b59eb255c703c6cbc5fafe2
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f88d707dbb
commit
896a90aa26
@@ -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';
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FlipperPluginID>) => 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<T> = (
|
||||
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<FlipperPluginID, FlipperPlugin> = 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<string, (any) => void> = new Map();
|
||||
|
||||
registerPlugins = (plugins: Array<FlipperPluginID>) => {
|
||||
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);
|
||||
}
|
||||
@@ -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==
|
||||
@@ -16,7 +16,6 @@
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"app",
|
||||
"app/src/utils/js-client",
|
||||
"babel-transformer",
|
||||
"doctor",
|
||||
"headless",
|
||||
|
||||
4
flipper-js-client-sdk/.gitignore
vendored
Normal file
4
flipper-js-client-sdk/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
lib/
|
||||
node_modules/
|
||||
*.tsbuildinfo
|
||||
/coverage
|
||||
21
flipper-js-client-sdk/LICENSE
Normal file
21
flipper-js-client-sdk/LICENSE
Normal file
@@ -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.
|
||||
34
flipper-js-client-sdk/README.md
Normal file
34
flipper-js-client-sdk/README.md
Normal file
@@ -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'})
|
||||
|
||||
```
|
||||
28
flipper-js-client-sdk/package.json
Normal file
28
flipper-js-client-sdk/package.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
147
flipper-js-client-sdk/src/api.ts
Normal file
147
flipper-js-client-sdk/src/api.ts
Normal file
@@ -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<T> = (
|
||||
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<T>(method: FlipperMethodID, receiver: FlipperReceiver<T>) {
|
||||
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<FlipperPluginID, FlipperPlugin> = 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: <T>(
|
||||
plugin: FlipperPluginID,
|
||||
method: FlipperMethodID,
|
||||
handler: (message: T) => void,
|
||||
) => void;
|
||||
|
||||
abstract isAvailable: () => boolean;
|
||||
}
|
||||
50
flipper-js-client-sdk/src/example.ts
Normal file
50
flipper-js-client-sdk/src/example.ts
Normal file
@@ -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;
|
||||
}
|
||||
10
flipper-js-client-sdk/src/index.ts
Normal file
10
flipper-js-client-sdk/src/index.ts
Normal file
@@ -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';
|
||||
58
flipper-js-client-sdk/src/webviewImpl.ts
Normal file
58
flipper-js-client-sdk/src/webviewImpl.ts
Normal file
@@ -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<string, (message: any) => 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();
|
||||
}
|
||||
32
flipper-js-client-sdk/tsconfig.json
Normal file
32
flipper-js-client-sdk/tsconfig.json
Normal file
@@ -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__/*"
|
||||
]
|
||||
}
|
||||
8
flipper-js-client-sdk/yarn.lock
Normal file
8
flipper-js-client-sdk/yarn.lock
Normal file
@@ -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==
|
||||
Reference in New Issue
Block a user