feat: support client api to wasm (#426)
* feat: support client api to wasm * fix: cargo fmt * fix: delete github config * fix: readme * feat: add wasm ci * fix: code review * fix: add test * fix: add sign in test * fix: test error --------- Co-authored-by: root <root@DESKTOP-RCFUF7L> Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
parent
a98f3951ca
commit
3bf5fb057d
|
|
@ -0,0 +1,40 @@
|
|||
name: WASM CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
NODE_VERSION: '20.12.0'
|
||||
RUST_TOOLCHAIN: "1.75"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: |
|
||||
AppFlowy-Cloud
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: npm install -g wasm-pack
|
||||
|
||||
- name: Build with wasm-pack
|
||||
run: wasm-pack build
|
||||
working-directory: ./libs/client-api-wasm
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
name: Manual NPM Package Publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
working_directory:
|
||||
description: 'Working directory (e.g., libs/client-api-wasm)'
|
||||
required: true
|
||||
default: 'libs/client-api-wasm'
|
||||
package_name:
|
||||
description: 'Package name'
|
||||
required: true
|
||||
default: '@appflowyinc/client-api-wasm'
|
||||
package_version:
|
||||
description: 'Package version'
|
||||
required: true
|
||||
env:
|
||||
NODE_VERSION: '20.12.0'
|
||||
RUST_TOOLCHAIN: "1.75"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_TOOLCHAIN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: |
|
||||
AppFlowy-Cloud
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: npm install -g wasm-pack
|
||||
|
||||
- name: Build with wasm-pack
|
||||
run: wasm-pack build
|
||||
working-directory: ${{ github.event.inputs.working_directory }}
|
||||
|
||||
- name: Update package.json
|
||||
run: |
|
||||
cd ${{ github.event.inputs.working_directory }}/pkg
|
||||
jq '.name = "${{ github.event.inputs.package_name }}" | .version = "${{ github.event.inputs.package_version }}"' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
- name: Configure npm for wasm-pack
|
||||
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ${{ github.event.inputs.working_directory }}/pkg/.npmrc
|
||||
|
||||
- name: Publish package
|
||||
run: |
|
||||
npm config set access public
|
||||
wasm-pack publish
|
||||
working-directory: ${{ github.event.inputs.working_directory }}/pkg
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
|
@ -512,9 +512,11 @@ dependencies = [
|
|||
"sqlx",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tsify",
|
||||
"url",
|
||||
"uuid",
|
||||
"validator",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1381,6 +1383,26 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "client-api-wasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"client-api",
|
||||
"console_error_panic_hook",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-wasm",
|
||||
"tsify",
|
||||
"uuid",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "client-websocket"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2493,6 +2515,19 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-utils"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gotrue"
|
||||
version = "0.1.0"
|
||||
|
|
@ -4924,18 +4959,29 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.195"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.195"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5967,6 +6013,17 @@ dependencies = [
|
|||
"tracing-serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-wasm"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "triomphe"
|
||||
version = "0.1.11"
|
||||
|
|
@ -5979,6 +6036,31 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tsify"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6b26cf145f2f3b9ff84e182c448eaf05468e247f148cf3d2a7d67d78ff023a0"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tsify-macros",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tsify-macros"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a94b0f0954b3e59bfc2c246b4c8574390d94a4ad4ad246aaf2fb07d7dfd3b47"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.20.1"
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ members = [
|
|||
# services
|
||||
"services/collab-history",
|
||||
"services/realtime",
|
||||
"libs/client-api-wasm"
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
|
|
|
|||
|
|
@ -34,4 +34,6 @@ gotrue_error= []
|
|||
bincode_error = ["bincode"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
getrandom = { version = "0.2", features = ["js"]}
|
||||
getrandom = { version = "0.2", features = ["js"]}
|
||||
tsify = "0.4.5"
|
||||
wasm-bindgen = "0.2.84"
|
||||
|
|
@ -231,6 +231,7 @@ impl From<crate::gotrue::GoTrueError> for AppError {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", derive(tsify::Tsify))]
|
||||
#[derive(
|
||||
Eq,
|
||||
PartialEq,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
bin/
|
||||
pkg/
|
||||
wasm-pack.log
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
[package]
|
||||
name = "client-api-wasm"
|
||||
version = "0.1.0"
|
||||
authors = ["Admin"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "0.2.84"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
log = "0.4.20"
|
||||
serde = "1.0.197"
|
||||
serde_json = "1.0.64"
|
||||
client-api = { path = "../client-api" }
|
||||
lazy_static = "1.4.0"
|
||||
wasm-bindgen-futures = "0.4.20"
|
||||
tsify = "0.4.5"
|
||||
tracing.workspace = true
|
||||
tracing-core = { version = "0.1.32" }
|
||||
tracing-wasm = "0.2.1"
|
||||
uuid.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.34"
|
||||
|
||||
[profile.release]
|
||||
# Tell `rustc` to optimize for small code size.
|
||||
opt-level = "s"
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<div align="center">
|
||||
|
||||
<h1><code>Client API WASM</code></h1>
|
||||
|
||||
<strong>Client-API to WebAssembly Compiler</strong>
|
||||
|
||||
</div>
|
||||
|
||||
## 🚴 Usage
|
||||
|
||||
### 🐑 Prepare
|
||||
|
||||
```bash
|
||||
# Clone the repository (if you haven't already)
|
||||
git clone https://github.com/AppFlowy-IO/AppFlowy-Cloud.git
|
||||
|
||||
# Navigate to the client-for-wasm directory
|
||||
cd libs/client-api-wasm
|
||||
|
||||
# Install the dependencies (if you haven't already)
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
### 🛠️ Build with `wasm-pack build`
|
||||
|
||||
```
|
||||
wasm-pack build
|
||||
```
|
||||
|
||||
### 🔬 Test in Headless Browsers with `wasm-pack test`
|
||||
|
||||
```bash
|
||||
# Ensure you have geckodriver installed
|
||||
wasm-pack test --headless --firefox
|
||||
|
||||
# or
|
||||
# Ensure you have chromedriver installed
|
||||
# https://googlechromelabs.github.io/chrome-for-testing/
|
||||
# Example (Linux):
|
||||
# 1. wget https://storage.googleapis.com/chrome-for-testing-public/123.0.6312.86/linux64/chromedriver-linux64.zip
|
||||
# 2. unzip chromedriver-linux64.zip
|
||||
# 3. sudo mv chromedriver /usr/local/bin
|
||||
# 4. chromedriver -v
|
||||
# If you see the version, then you have successfully installed chromedriver
|
||||
# Note: the version of chromedriver should match the version of chrome installed on your system
|
||||
wasm-pack test --headless --chrome
|
||||
```
|
||||
|
||||
### 🎁 Publish to NPM with ~~`wasm-pack publish`~~
|
||||
|
||||
##### Don't publish in local development, only publish in github actions
|
||||
|
||||
```
|
||||
wasm-pack publish
|
||||
```
|
||||
|
||||
### 📦 Use your package as a dependency
|
||||
|
||||
```
|
||||
npm install --save @appflowy/client-api-for-wasm
|
||||
```
|
||||
|
||||
### 📝 How to use the package in development?
|
||||
|
||||
See the [README.md](https://github.com/AppFlowy-IO/AppFlowy/tree/main/frontend/appflowy_web_app/README.md) in the AppFlowy Repository.
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
use client_api::error::ErrorCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tsify::Tsify;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
macro_rules! from_struct_for_jsvalue {
|
||||
($type:ty) => {
|
||||
impl From<$type> for JsValue {
|
||||
fn from(value: $type) -> Self {
|
||||
JsValue::from_str(&serde_json::to_string(&value).unwrap())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Tsify, Serialize, Deserialize, Default, Debug)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct Configuration {
|
||||
pub compression_quality: u32,
|
||||
pub compression_buffer_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Tsify, Serialize, Deserialize, Default, Debug)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct ClientAPIConfig {
|
||||
pub base_url: String,
|
||||
pub ws_addr: String,
|
||||
pub gotrue_url: String,
|
||||
pub device_id: String,
|
||||
pub configuration: Option<Configuration>,
|
||||
pub client_id: String,
|
||||
}
|
||||
|
||||
#[derive(Tsify, Serialize, Deserialize, Default, Debug)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct ClientResponse {
|
||||
pub code: ErrorCode,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
from_struct_for_jsvalue!(ClientResponse);
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
pub mod entities;
|
||||
use crate::entities::{ClientAPIConfig, ClientResponse};
|
||||
use client_api::{Client, ClientConfiguration};
|
||||
use tracing;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = "wee_alloc")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(msg: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(msg: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn info(msg: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn debug(msg: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn warn(msg: &str);
|
||||
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn trace(msg: &str);
|
||||
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct ClientAPI {
|
||||
client: Client,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl ClientAPI {
|
||||
pub fn new(config: ClientAPIConfig) -> ClientAPI {
|
||||
tracing_wasm::set_as_global_default();
|
||||
let configuration = ClientConfiguration::default();
|
||||
|
||||
if let Some(compression) = &config.configuration {
|
||||
configuration
|
||||
.to_owned()
|
||||
.with_compression_buffer_size(compression.compression_buffer_size)
|
||||
.with_compression_quality(compression.compression_quality);
|
||||
}
|
||||
|
||||
let client = Client::new(
|
||||
config.base_url.as_str(),
|
||||
config.ws_addr.as_str(),
|
||||
config.gotrue_url.as_str(),
|
||||
config.device_id.as_str(),
|
||||
configuration,
|
||||
config.client_id.as_str(),
|
||||
);
|
||||
tracing::debug!("Client API initialized, config: {:?}", config);
|
||||
ClientAPI { client }
|
||||
}
|
||||
|
||||
// pub async fn get_user(&self) -> ClientResponse {
|
||||
// if let Err(err) = self.client.get_profile().await {
|
||||
// log::error!("Get user failed: {:?}", err);
|
||||
// return ClientResponse<bool> {
|
||||
// code: ClientErrorCode::from(err.code),
|
||||
// message: err.message.to_string(),
|
||||
// data: None
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log::info!("Get user success");
|
||||
// ClientResponse {
|
||||
// code: ClientErrorCode::Ok,
|
||||
// message: "Get user success".to_string(),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub async fn sign_up_email_verified(
|
||||
&self,
|
||||
email: &str,
|
||||
password: &str,
|
||||
) -> Result<bool, ClientResponse> {
|
||||
if let Err(err) = self.client.sign_up(email, password).await {
|
||||
return Err(ClientResponse {
|
||||
code: err.code,
|
||||
message: err.message.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub async fn sign_in_password(
|
||||
&self,
|
||||
email: &str,
|
||||
password: &str,
|
||||
) -> Result<bool, ClientResponse> {
|
||||
if let Err(err) = self.client.sign_in_password(email, password).await {
|
||||
return Err(ClientResponse {
|
||||
code: err.code,
|
||||
message: err.message.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
extern crate wasm_bindgen_test;
|
||||
use wasm_bindgen_test::wasm_bindgen_test_configure;
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use client_api_test_util::{generate_unique_email, localhost_client};
|
||||
use client_api_test_util::{generate_unique_email, localhost_client, TestClient};
|
||||
use wasm_bindgen_test::wasm_bindgen_test;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
|
|
@ -8,3 +8,20 @@ async fn wasm_sign_up_success() {
|
|||
let c = localhost_client();
|
||||
c.sign_up(&email, password).await.unwrap();
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
async fn wasm_sign_in_success() {
|
||||
let test_client = TestClient::new_user().await;
|
||||
let user = test_client.user;
|
||||
|
||||
let res = test_client
|
||||
.api_client
|
||||
.sign_in_password(user.email.as_str(), user.password.as_str())
|
||||
.await;
|
||||
|
||||
assert!(res.ok());
|
||||
|
||||
let val = res.unwrap();
|
||||
|
||||
assert!(val);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue