Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
cert.csr
cert.der
/firedbg
.vscode/ltex.*
.vscode/ltex.*
pkg/
wasm-pack.log
12 changes: 11 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"markiscodecoverage.searchCriteria": ".coverage/lcov*.info",
"rust-analyzer.cargo.features": ["types", "reqwest", "gateway", "serde"]
// "rust-analyzer.cargo.features": ["types", "reqwest", "gateway", "serde"]
"rust-analyzer.cargo.features": [
"_wasm_bindgen",
"wasm",
"types",
"reqwest",
"gateway",
"serde"
],
"rust-analyzer.cargo.noDefaultFeatures": true,
"rust-analyzer.cargo.target": "wasm32-unknown-unknown"
}
22 changes: 20 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repository = "https://github.com/polyphony-chat/polyproto"
rust-version = "1.85.0"

[lib]
crate-type = ["rlib", "cdylib", "staticlib"]
crate-type = ["cdylib", "rlib"]

[features]
default = ["types", "serde", "gateway", "tokio/net"]
Expand All @@ -20,6 +20,8 @@ serde = ["dep:serde", "serde_json", "serde_with", "url/serde"]
serde_with = ["dep:serde_with"]
serde_json = ["dep:serde_json"]
gateway = ["serde", "types"]
_wasm_bindgen = ["wasm", "dep:wasm-bindgen", "dep:js-sys", "dep:wee_alloc"]
__no_wee_alloc = []

[dependencies]
der = { version = "0.7.9", features = ["pem"] }
Expand Down Expand Up @@ -50,6 +52,11 @@ futures-util = "0.3.31"
urlencoding = "2.1.3"
ws_stream_wasm = { version = "*", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2.100", optional = true }
js-sys = { version = "0.3.77", optional = true }
wee_alloc = { version = "0.4.5", optional = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
rustls = "0.23.25"
tokio-tungstenite = { version = "0.26.2", features = [
Expand All @@ -73,7 +80,18 @@ httptest = "0.16.3"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.50"
wasm-bindgen = "0.2.100"
# 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" }

[target.'cfg(target_arch = "wasm32")'.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
lto = true
codegen-units = 1
panic = "abort"

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
8 changes: 8 additions & 0 deletions headaches.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Headaches involving `wasm-bindgen` and overall Rust ⇾ TS/JS bindgen

- `wasm-bindgen` does not support traits, or struct generics with trait bounds like `struct X<S: TraitImplementer>`
- Crates like `ts_rs` might help but would require a more complex build process to assemble a finished TS/JS project
- Worst case: Manually write JS/TS code to bridge the things unsupported by other bindgen libs
- Would be immensely painful
- Other idea: LOADS of handwritten wrappers for Rust functions, also written in Rust but `wasm-bindgen` compatible.
- For traits like signature, we need to make an extremely generic impl that can be somehow instantiated from js/ts
40 changes: 40 additions & 0 deletions scripts/wasm-pack-helper
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

# check number of arguments
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
echo "Error: Invalid number of arguments. Usage: $0 <build|pack|publish> [release|debug]"
exit 1
fi

command=$1
mode=${2:-"debug"}

# validate if arg #1 is valid
if [[ "$command" != "build" && "$command" != "pack" && "$command" != "publish" ]]; then
echo "Error: First argument must be one of 'build', 'pack', or 'publish'."
exit 1
fi

# same for arg #2
if [[ "$mode" != "release" && "$mode" != "debug" ]]; then
echo "Error: Second argument must be either 'release' or 'debug'. Defaulting to 'debug'."
mode="debug"
fi

# wasm-pack check
if ! command -v wasm-pack &> /dev/null; then
# prompt user to install wasm-pack
read -p "wasm-pack could not be found. Do you want to install it? (y/n): " install_wasm_pack
if [[ "$install_wasm_pack" == [Yy]* ]]; then
cargo install wasm-pack --force
else
echo "Error: wasm-pack is required for this script."
exit 1
fi
fi

# Execute the wasm-pack command
wasm-pack $command --$mode --no-default-features --features=wasm,reqwest,serde,types,_wasm_bindgen
4 changes: 3 additions & 1 deletion src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ pub trait PublicKey<S: Signature>: PartialEq + Eq + Clone {
S::algorithm_identifier()
}
/// Creates a new [Self] from a [PublicKeyInfo].
fn try_from_public_key_info(public_key_info: PublicKeyInfo) -> Result<Self, CertificateConversionError>;
fn try_from_public_key_info(
public_key_info: PublicKeyInfo,
) -> Result<Self, CertificateConversionError>;
}
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ of this project.
clippy::todo
)]

#[cfg(all(
target_arch = "wasm32",
feature = "_wasm_bindgen",
not(feature = "__no_wee_alloc")
))]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

/// The OID for the `domainComponent` RDN
pub const OID_RDN_DOMAIN_COMPONENT: &str = "0.9.2342.19200300.100.1.25";
/// The OID for the `commonName` RDN
Expand Down Expand Up @@ -168,6 +176,10 @@ pub mod signature;
/// Types used in polyproto and the polyproto HTTP/REST APIs
pub mod types;

#[cfg(all(target_arch = "wasm32", feature = "_wasm_bindgen"))]
/// 🚧 Under construction! 👷 Module for exporting polyproto to JS/TS.
pub mod wasm_bindgen;

mod constraints;

pub use der;
Expand Down
11 changes: 11 additions & 0 deletions src/wasm_bindgen/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use wasm_bindgen::prelude::*;

#[derive(Debug, Clone, Copy)]
#[wasm_bindgen(js_name = "PolyprotoError")]
pub enum JsConstraintError {
InvalidInput,
}
8 changes: 8 additions & 0 deletions src/wasm_bindgen/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

pub mod errors;
pub mod types;

mod utils;
40 changes: 40 additions & 0 deletions src/wasm_bindgen/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::types::DomainName as RDomainName;
use crate::types::FederationId as RFederationId;
use wasm_bindgen::prelude::*;

use super::errors::JsConstraintError;

#[derive(Clone, Debug)]
#[wasm_bindgen(inspectable)]
/// A `FederationId` is a globally unique identifier for an actor in the context of polyproto.
pub struct FederationId {
#[wasm_bindgen(skip)]
_inner: RFederationId,
}

#[wasm_bindgen]
impl FederationId {
#[wasm_bindgen(constructor)]
/// Validates input, then creates a new `FederationId`. Throws an error if input validation fails.
pub fn new(id: &str) -> Result<FederationId, JsConstraintError> {
Ok(FederationId {
_inner: RFederationId::new(id).map_err(|_| JsConstraintError::InvalidInput)?,
})
}

#[wasm_bindgen(js_name = "toJSON")]
pub fn js_to_json(&self) -> String {
self._inner.to_string()
}
}

#[derive(Debug, Clone)]
#[wasm_bindgen(inspectable)]
pub struct DomainName {
#[wasm_bindgen(skip)]
_inner: RDomainName,
}
14 changes: 14 additions & 0 deletions src/wasm_bindgen/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
// we will get better error messages if our code ever panics.
//
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}