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
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