mirror of
https://github.com/aljazceru/pubky-core.git
synced 2025-12-17 05:54:20 +01:00
feat(client): Set Relays in the JS Client Config (#139)
* added js pubky client constructor config * fixed bugs * fmt and cargotoml * moved wasm constructor order * removed pubky-common reexport of client
This commit is contained in:
committed by
GitHub
parent
9b8e1ab8c9
commit
a485d8c2f4
10
.github/workflows/pr-check.yml
vendored
10
.github/workflows/pr-check.yml
vendored
@@ -114,10 +114,18 @@ jobs:
|
||||
|
||||
- name: Wait for testnet homeserver
|
||||
run: |
|
||||
timeout=180
|
||||
count=0
|
||||
until nc -zv 127.0.0.1 6288; do
|
||||
echo "Waiting for testnet homeserver to be ready..."
|
||||
if [ $count -ge $timeout ]; then
|
||||
echo "Timeout: Testnet homeserver did not start within 3 minutes."
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting for testnet homeserver to be ready... ($count/$timeout)"
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
echo "Testnet homeserver is ready."
|
||||
|
||||
- name: Run Tests (only node-js)
|
||||
working-directory: pubky-client/pkg
|
||||
|
||||
64
Cargo.lock
generated
64
Cargo.lock
generated
@@ -860,7 +860,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pkarr",
|
||||
"pubky-common",
|
||||
"pubky-testnet",
|
||||
"reqwest",
|
||||
"tokio",
|
||||
@@ -1191,6 +1190,19 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-utils"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "governor"
|
||||
version = "0.8.0"
|
||||
@@ -2400,10 +2412,13 @@ dependencies = [
|
||||
"pkarr",
|
||||
"pubky-common",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tsify",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
@@ -3024,6 +3039,17 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bencode"
|
||||
version = "0.2.4"
|
||||
@@ -3054,6 +3080,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.139"
|
||||
@@ -3724,6 +3761,31 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tsify"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ec91b85e6c6592ed28636cb1dd1fac377ecbbeb170ff1d79f97aac5e38926d"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tsify-macros",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tsify-macros"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a324606929ad11628a19206d7853807481dcaecd6c08be70a235930b8241955"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
|
||||
@@ -6,7 +6,6 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
pubky-testnet = { workspace = true }
|
||||
pubky-common = { workspace = true }
|
||||
tokio = { version = "1.43.0", features = ["full", "test-util"] }
|
||||
tracing-subscriber = "0.3.19"
|
||||
pkarr = {workspace = true}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use pkarr::Keypair;
|
||||
use pubky_common::capabilities::{Capabilities, Capability};
|
||||
use pubky_testnet::pubky_common::capabilities::{Capabilities, Capability};
|
||||
use pubky_testnet::{
|
||||
pubky_homeserver::{MockDataDir, SignupMode},
|
||||
EphemeralTestnet, Testnet,
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
[package]
|
||||
name = "pubky"
|
||||
description = "Pubky-Core Client"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
version = "0.5.0-rc.0"
|
||||
edition = "2024"
|
||||
authors = [
|
||||
"SeverinAlexB <severin@synonym.to>",
|
||||
"SHAcollision <shacollision@synonym.to>",
|
||||
"Nuh <nuh@nuh.dev>"
|
||||
]
|
||||
license = "MIT"
|
||||
homepage = "https://github.com/pubky/pubky-core"
|
||||
repository = "https://github.com/pubky/pubky-core"
|
||||
|
||||
keywords = ["web", "dht", "dns", "decentralized", "identity"]
|
||||
categories = [
|
||||
"network-programming",
|
||||
@@ -25,7 +30,7 @@ wasm-bindgen = "0.2.100"
|
||||
url = "2.5.4"
|
||||
bytes = "^1.10.0"
|
||||
base64 = "0.22.1"
|
||||
pkarr = { workspace = true, features = ["full"] }
|
||||
pkarr = {version = "3.7.1", features = ["full"] }
|
||||
cookie = "0.18.1"
|
||||
tracing = "0.1.41"
|
||||
cookie_store = { version = "0.21.1", default-features = false }
|
||||
@@ -52,7 +57,9 @@ wasm-bindgen-futures = "0.4.50"
|
||||
console_log = { version = "1.0.0", features = ["color"] }
|
||||
log = "0.4.25"
|
||||
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.4"
|
||||
tsify = "0.5.5"
|
||||
js-sys = "0.3.77"
|
||||
web-sys = "0.3.77"
|
||||
|
||||
@@ -61,7 +68,7 @@ anyhow = "1.0.95"
|
||||
futures-lite = "2.6.0"
|
||||
tokio = "1.43.0"
|
||||
tracing-subscriber = "0.3.19"
|
||||
mainline = { workspace = true }
|
||||
mainline = { version = "5.4.0" }
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases = "0.2.1"
|
||||
|
||||
35
pubky-client/pkg/test/constructor.js
Normal file
35
pubky-client/pkg/test/constructor.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import test from 'tape'
|
||||
|
||||
import { Client } from '../index.cjs'
|
||||
|
||||
|
||||
|
||||
|
||||
test('new Client() without config', async (t) => {
|
||||
const client = new Client(); // Should always work
|
||||
t.ok(client, "should create a client");
|
||||
});
|
||||
|
||||
test('new Client() with config', async (t) => {
|
||||
const client = new Client({
|
||||
pkarr: {
|
||||
relays: ['http://localhost:15412/relay'],
|
||||
requestTimeout: 1000
|
||||
},
|
||||
userMaxRecordAge: 1000
|
||||
});
|
||||
t.ok(client, "should create a client");
|
||||
});
|
||||
|
||||
test('new Client() partial config', async (t) => {
|
||||
const client = new Client({
|
||||
userMaxRecordAge: 1000
|
||||
});
|
||||
t.ok(client, "should create a client");
|
||||
});
|
||||
|
||||
test('new Client() with faulty config', async (t) => {
|
||||
t.throws(() => new Client({
|
||||
userMaxRecordAge: 0 // Zero is invalid
|
||||
}), "should throw an error");
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'tape'
|
||||
|
||||
import { Keypair } from '../index.cjs'
|
||||
import { Keypair, PublicKey } from '../index.cjs'
|
||||
|
||||
test('generate keys from a seed', async (t) => {
|
||||
const secretkey = Buffer.from('5aa93b299a343aa2691739771f2b5b85e740ca14c685793d67870f88fa89dc51', 'hex')
|
||||
@@ -16,6 +16,18 @@ test('fromSecretKey error', async (t) => {
|
||||
const secretkey = Buffer.from('5aa93b299a343aa2691739771f2b5b', 'hex')
|
||||
|
||||
|
||||
t.throws(() => Keypair.fromSecretKey(null), /Expected secret_key to be an instance of Uint8Array/)
|
||||
t.throws(() => Keypair.fromSecretKey(null), "Expected secret_key to be an instance of Uint8Array");
|
||||
t.throws(() => Keypair.fromSecretKey(secretkey), /Expected secret_key to be 32 bytes, got 15/)
|
||||
})
|
||||
|
||||
test('PublicKey from and toUint8Array', async (t) => {
|
||||
const z32 = "gcumbhd7sqit6nn457jxmrwqx9pyymqwamnarekgo3xppqo6a19o";
|
||||
const publicKey = PublicKey.from(z32)
|
||||
t.is(publicKey.z32(), z32)
|
||||
t.deepEqual(publicKey.toUint8Array(), Uint8Array.from([
|
||||
51, 38, 176, 240, 125, 179, 171, 31,
|
||||
8, 90, 223, 82, 245, 146, 142, 127,
|
||||
218, 0, 45, 212, 194, 197, 130, 33,
|
||||
70, 134, 94, 214, 186, 30, 196, 191
|
||||
]));
|
||||
})
|
||||
|
||||
@@ -19,17 +19,18 @@ macro_rules! cross_debug {
|
||||
}
|
||||
|
||||
pub mod native;
|
||||
mod shared;
|
||||
#[cfg(wasm_browser)]
|
||||
mod wasm;
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub use crate::native::Client;
|
||||
pub use crate::native::{api::auth::AuthRequest, api::public::ListBuilder, ClientBuilder};
|
||||
pub use crate::native::{ClientBuilder, api::auth::AuthRequest, api::public::ListBuilder};
|
||||
|
||||
#[cfg(wasm_browser)]
|
||||
pub use native::Client as NativeClient;
|
||||
#[cfg(wasm_browser)]
|
||||
pub use wasm::Client;
|
||||
pub use wasm::constructor::Client;
|
||||
|
||||
// Re-exports
|
||||
pub use pkarr::{Keypair, PublicKey};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use base64::{alphabet::URL_SAFE, engine::general_purpose::NO_PAD, Engine};
|
||||
use base64::{Engine, alphabet::URL_SAFE, engine::general_purpose::NO_PAD};
|
||||
use reqwest::{IntoUrl, Method, StatusCode};
|
||||
use url::Url;
|
||||
|
||||
@@ -14,7 +14,7 @@ use pubky_common::{
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use super::super::{internal::pkarr::PublishStrategy, Client};
|
||||
use super::super::{Client, internal::pkarr::PublishStrategy};
|
||||
use crate::handle_http_error;
|
||||
|
||||
impl Client {
|
||||
@@ -398,11 +398,12 @@ impl AuthRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pkarr::Keypair;
|
||||
|
||||
use crate::{native::internal::pkarr::PublishStrategy, Client};
|
||||
use crate::{Client, native::internal::pkarr::PublishStrategy};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_homeserver() {
|
||||
|
||||
4
pubky-client/src/native/api/mod.rs
Normal file
4
pubky-client/src/native/api/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod auth;
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub mod http;
|
||||
pub mod public;
|
||||
@@ -1,17 +1,7 @@
|
||||
pub mod internal {
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub mod cookies;
|
||||
pub mod pkarr;
|
||||
}
|
||||
pub mod api {
|
||||
pub mod auth;
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub mod http;
|
||||
pub mod public;
|
||||
}
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
use super::internal::cookies::CookieJar;
|
||||
#[cfg(not(wasm_browser))]
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -90,7 +80,7 @@ impl ClientBuilder {
|
||||
let pkarr = self.pkarr.build()?;
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
let cookie_store = Arc::new(internal::cookies::CookieJar::default());
|
||||
let cookie_store = Arc::new(CookieJar::default());
|
||||
|
||||
// TODO: allow custom user agent, but force a Pubky user agent information
|
||||
let user_agent = DEFAULT_USER_AGENT;
|
||||
@@ -156,7 +146,7 @@ pub struct Client {
|
||||
pub(crate) pkarr: pkarr::Client,
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub(crate) cookie_store: std::sync::Arc<internal::cookies::CookieJar>,
|
||||
pub(crate) cookie_store: std::sync::Arc<CookieJar>,
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub(crate) icann_http: reqwest::Client,
|
||||
|
||||
@@ -183,6 +173,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
use pkarr::PublicKey;
|
||||
use reqwest::{cookie::CookieStore, header::HeaderValue, Response};
|
||||
use reqwest::{Response, cookie::CookieStore, header::HeaderValue};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CookieJar {
|
||||
|
||||
3
pubky-client/src/native/internal/mod.rs
Normal file
3
pubky-client/src/native/internal/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
#[cfg(not(wasm_browser))]
|
||||
pub mod cookies;
|
||||
pub mod pkarr;
|
||||
@@ -1,20 +1,15 @@
|
||||
use anyhow::Result;
|
||||
use pkarr::{
|
||||
Keypair, SignedPacket, Timestamp,
|
||||
dns::rdata::{RData, SVCB},
|
||||
errors::QueryError,
|
||||
Keypair, SignedPacket, Timestamp,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::super::Client;
|
||||
use crate::shared::sleep;
|
||||
|
||||
// sleep for native
|
||||
#[cfg(not(wasm_browser))]
|
||||
use tokio::time::sleep;
|
||||
// sleep for wasm
|
||||
#[cfg(wasm_browser)]
|
||||
use gloo_timers::future::sleep;
|
||||
use super::super::Client;
|
||||
|
||||
/// Helper returns true if this error (or any of its sources) is one of our
|
||||
/// three recoverable `QueryError`s with simple retrial.
|
||||
@@ -150,12 +145,13 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(wasm_browser))]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::Client;
|
||||
use pkarr::dns::rdata::SVCB;
|
||||
use pkarr::Keypair;
|
||||
use pkarr::dns::rdata::SVCB;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_host_from_packet() -> Result<()> {
|
||||
|
||||
4
pubky-client/src/native/mod.rs
Normal file
4
pubky-client/src/native/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod api;
|
||||
mod client;
|
||||
pub mod internal;
|
||||
pub use client::*;
|
||||
2
pubky-client/src/shared/mod.rs
Normal file
2
pubky-client/src/shared/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod sleep;
|
||||
pub use sleep::*;
|
||||
14
pubky-client/src/shared/sleep.rs
Normal file
14
pubky-client/src/shared/sleep.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
// sleep for native
|
||||
#[cfg(not(wasm_browser))]
|
||||
use tokio::time::sleep as inner_sleep;
|
||||
// sleep for wasm
|
||||
#[cfg(wasm_browser)]
|
||||
use gloo_timers::future::sleep as inner_sleep;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
/// Sleep for the given duration.
|
||||
/// Works on both native and wasm.
|
||||
pub async fn sleep(duration: Duration) {
|
||||
inner_sleep(duration).await;
|
||||
}
|
||||
@@ -4,12 +4,15 @@ use url::Url;
|
||||
|
||||
use pubky_common::capabilities::Capabilities;
|
||||
|
||||
use crate::wasm::wrappers::{
|
||||
keys::{Keypair, PublicKey},
|
||||
session::Session,
|
||||
use crate::wasm::{
|
||||
js_result::JsResult,
|
||||
wrappers::{
|
||||
keys::{Keypair, PublicKey},
|
||||
session::Session,
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::Client;
|
||||
use super::super::constructor::Client;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@@ -25,7 +28,7 @@ impl Client {
|
||||
keypair: &Keypair,
|
||||
homeserver: &PublicKey,
|
||||
signup_token: Option<String>,
|
||||
) -> Result<Session, JsValue> {
|
||||
) -> JsResult<Session> {
|
||||
Ok(Session(
|
||||
self.0
|
||||
.signup(
|
||||
@@ -43,7 +46,7 @@ impl Client {
|
||||
/// Returns [Session] or `None` (if received `404 NOT_FOUND`),
|
||||
/// or throws the received error if the response has any other `>=400` status code.
|
||||
#[wasm_bindgen]
|
||||
pub async fn session(&self, pubky: &PublicKey) -> Result<Option<Session>, JsValue> {
|
||||
pub async fn session(&self, pubky: &PublicKey) -> JsResult<Option<Session>> {
|
||||
self.0
|
||||
.session(pubky.as_inner())
|
||||
.await
|
||||
@@ -53,7 +56,7 @@ impl Client {
|
||||
|
||||
/// Signout from a homeserver.
|
||||
#[wasm_bindgen]
|
||||
pub async fn signout(&self, pubky: &PublicKey) -> Result<(), JsValue> {
|
||||
pub async fn signout(&self, pubky: &PublicKey) -> JsResult<()> {
|
||||
self.0
|
||||
.signout(pubky.as_inner())
|
||||
.await
|
||||
@@ -62,7 +65,7 @@ impl Client {
|
||||
|
||||
/// Signin to a homeserver using the root Keypair.
|
||||
#[wasm_bindgen]
|
||||
pub async fn signin(&self, keypair: &Keypair) -> Result<(), JsValue> {
|
||||
pub async fn signin(&self, keypair: &Keypair) -> JsResult<()> {
|
||||
self.0
|
||||
.signin(keypair.as_inner())
|
||||
.await
|
||||
@@ -76,7 +79,7 @@ impl Client {
|
||||
///
|
||||
/// Returns a [AuthRequest]
|
||||
#[wasm_bindgen(js_name = "authRequest")]
|
||||
pub fn auth_request(&self, relay: &str, capabilities: &str) -> Result<AuthRequest, JsValue> {
|
||||
pub fn auth_request(&self, relay: &str, capabilities: &str) -> JsResult<AuthRequest> {
|
||||
let auth_request = self
|
||||
.0
|
||||
.auth_request(
|
||||
@@ -91,11 +94,7 @@ impl Client {
|
||||
/// Sign an [pubky_common::auth::AuthToken], encrypt it and send it to the
|
||||
/// source of the pubkyauth request url.
|
||||
#[wasm_bindgen(js_name = "sendAuthToken")]
|
||||
pub async fn send_auth_token(
|
||||
&self,
|
||||
keypair: &Keypair,
|
||||
pubkyauth_url: &str,
|
||||
) -> Result<(), JsValue> {
|
||||
pub async fn send_auth_token(&self, keypair: &Keypair, pubkyauth_url: &str) -> JsResult<()> {
|
||||
let pubkyauth_url: Url = pubkyauth_url.try_into().map_err(|_| "Invalid relay Url")?;
|
||||
|
||||
self.0
|
||||
@@ -110,14 +109,12 @@ impl Client {
|
||||
/// Looks up the pkarr packet for the given public key and returns the content of the first `_pubky` SVCB record.
|
||||
/// Throws an error if no homeserver is found.
|
||||
#[wasm_bindgen(js_name = "getHomeserver")]
|
||||
pub async fn get_homeserver(&self, public_key: &PublicKey) -> Result<PublicKey, JsValue> {
|
||||
let val = self.0.get_homeserver(public_key.as_inner()).await;
|
||||
if val.is_none() {
|
||||
return Err(JsValue::from_str("No homeserver found"));
|
||||
}
|
||||
let val = val.unwrap();
|
||||
let js_val = JsValue::from_str(val.as_str());
|
||||
PublicKey::try_from(js_val)
|
||||
pub async fn get_homeserver(&self, public_key: &PublicKey) -> JsResult<PublicKey> {
|
||||
let hs_z32 = match self.0.get_homeserver(public_key.as_inner()).await {
|
||||
Some(hs_z32) => hs_z32,
|
||||
None => return Err(JsValue::from_str("No homeserver found")),
|
||||
};
|
||||
PublicKey::try_from(hs_z32)
|
||||
}
|
||||
|
||||
/// Republish the user's PKarr record pointing to their homeserver.
|
||||
@@ -133,15 +130,11 @@ impl Client {
|
||||
/// republishing. On a failed signin due to homeserver resolution failure, a key
|
||||
/// manager should always attempt to republish the last known homeserver.
|
||||
#[wasm_bindgen(js_name = "republishHomeserver")]
|
||||
pub async fn republish_homeserver(
|
||||
&self,
|
||||
keypair: &Keypair,
|
||||
host: &PublicKey,
|
||||
) -> Result<(), JsValue> {
|
||||
pub async fn republish_homeserver(&self, keypair: &Keypair, host: &PublicKey) -> JsResult<()> {
|
||||
self.0
|
||||
.republish_homeserver(keypair.as_inner(), host.as_inner())
|
||||
.await
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()));
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -167,7 +160,7 @@ impl AuthRequest {
|
||||
///
|
||||
/// Otherwise it will throw an error.
|
||||
#[wasm_bindgen]
|
||||
pub async fn response(&self) -> Result<PublicKey, JsValue> {
|
||||
pub async fn response(&self) -> JsResult<PublicKey> {
|
||||
self.0
|
||||
.response()
|
||||
.await
|
||||
|
||||
@@ -8,10 +8,12 @@ use reqwest::{IntoUrl, Method, RequestBuilder, Url};
|
||||
|
||||
use futures_lite::StreamExt;
|
||||
|
||||
use pkarr::extra::endpoints::Endpoint;
|
||||
use pkarr::PublicKey;
|
||||
use pkarr::extra::endpoints::Endpoint;
|
||||
|
||||
use super::super::Client;
|
||||
use crate::wasm::js_result::JsResult;
|
||||
|
||||
use super::super::constructor::Client;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Client {
|
||||
@@ -20,7 +22,7 @@ impl Client {
|
||||
&self,
|
||||
url: &str,
|
||||
request_init: Option<RequestInit>,
|
||||
) -> Result<js_sys::Promise, JsValue> {
|
||||
) -> JsResult<js_sys::Promise> {
|
||||
let mut url: Url = url.try_into().map_err(|err| {
|
||||
JsValue::from_str(&format!("pubky::Client::fetch(): Invalid `url`; {:?}", err))
|
||||
})?;
|
||||
|
||||
4
pubky-client/src/wasm/api/mod.rs
Normal file
4
pubky-client/src/wasm/api/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod auth;
|
||||
pub mod http;
|
||||
pub mod public;
|
||||
pub mod recovery_file;
|
||||
@@ -3,7 +3,9 @@
|
||||
use js_sys::Array;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::super::Client;
|
||||
use crate::wasm::js_result::JsResult;
|
||||
|
||||
use super::super::constructor::Client;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Client {
|
||||
@@ -23,7 +25,7 @@ impl Client {
|
||||
reverse: Option<bool>,
|
||||
limit: Option<u16>,
|
||||
shallow: Option<bool>,
|
||||
) -> Result<Array, JsValue> {
|
||||
) -> JsResult<Array> {
|
||||
// TODO: try later to return Vec<String> from async function.
|
||||
|
||||
if let Some(cursor) = cursor {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use js_sys::Uint8Array;
|
||||
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
|
||||
use wasm_bindgen::prelude::{JsValue, wasm_bindgen};
|
||||
|
||||
use crate::wasm::wrappers::keys::Keypair;
|
||||
use crate::wasm::{js_result::JsResult, wrappers::keys::Keypair};
|
||||
|
||||
/// Create a recovery file of the `keypair`, containing the secret key encrypted
|
||||
/// using the `passphrase`.
|
||||
@@ -15,7 +15,7 @@ pub fn create_recovery_file(keypair: &Keypair, passphrase: &str) -> Uint8Array {
|
||||
/// Create a recovery file of the `keypair`, containing the secret key encrypted
|
||||
/// using the `passphrase`.
|
||||
#[wasm_bindgen(js_name = "decryptRecoveryFile")]
|
||||
pub fn decrypt_recovery_file(recovery_file: &[u8], passphrase: &str) -> Result<Keypair, JsValue> {
|
||||
pub fn decrypt_recovery_file(recovery_file: &[u8], passphrase: &str) -> JsResult<Keypair> {
|
||||
pubky_common::recovery_file::decrypt_recovery_file(recovery_file, passphrase)
|
||||
.map(Keypair::from)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||
|
||||
126
pubky-client/src/wasm/constructor.rs
Normal file
126
pubky-client/src/wasm/constructor.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use std::{num::NonZeroU64, time::Duration};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tsify::Tsify;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::js_result::JsResult;
|
||||
|
||||
static TESTNET_RELAYS: [&str; 1] = ["http://localhost:15411/"];
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// JS style config objects for the client.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
/// Pkarr Config
|
||||
#[derive(Tsify, Serialize, Deserialize, Debug)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PkarrConfig {
|
||||
/// The list of relays to access the DHT with.
|
||||
pub(crate) relays: Option<Vec<String>>,
|
||||
/// The timeout for DHT requests in milliseconds.
|
||||
/// Default is 2000ms.
|
||||
pub(crate) request_timeout: Option<NonZeroU64>,
|
||||
}
|
||||
|
||||
/// Pubky Client Config
|
||||
#[derive(Tsify, Serialize, Deserialize, Debug)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PubkyClientConfig {
|
||||
/// Configuration on how to access pkarr packets on the mainline DHT.
|
||||
pub(crate) pkarr: Option<PkarrConfig>,
|
||||
/// The maximum age of a record in seconds.
|
||||
/// If the user pkarr record is older than this, it will be automatically refreshed.
|
||||
pub(crate) user_max_record_age: Option<NonZeroU64>,
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// JS Client constructor
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Client(pub(crate) crate::NativeClient);
|
||||
|
||||
impl Default for Client {
|
||||
fn default() -> Self {
|
||||
Self::new(None).expect("No config constructor should be infallible")
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Client {
|
||||
#[wasm_bindgen(constructor)]
|
||||
/// Create a new Pubky Client with an optional configuration.
|
||||
pub fn new(config_opt: Option<PubkyClientConfig>) -> JsResult<Self> {
|
||||
let mut builder = crate::NativeClient::builder();
|
||||
|
||||
let config = match config_opt {
|
||||
Some(config) => config,
|
||||
None => {
|
||||
return Ok(Self(
|
||||
builder
|
||||
.build()
|
||||
.expect("building a default NativeClient should be infallible"),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(pkarr) = config.pkarr {
|
||||
// Set pkarr relays
|
||||
if let Some(relays) = pkarr.relays {
|
||||
let mut relay_set_error: Option<JsValue> = None;
|
||||
builder.pkarr(|pkarr_builder| {
|
||||
pkarr_builder.no_relays(); // Remove default pkarr config
|
||||
if let Err(e) = pkarr_builder.relays(&relays) {
|
||||
relay_set_error =
|
||||
Some(JsValue::from_str(&format!("Failed to set relays. {}", e)));
|
||||
}
|
||||
pkarr_builder
|
||||
});
|
||||
if let Some(e) = relay_set_error {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
// Set pkarr timeout
|
||||
if let Some(timeout) = pkarr.request_timeout {
|
||||
builder.pkarr(|pkarr_builder| {
|
||||
pkarr_builder.request_timeout(Duration::from_millis(timeout.get()));
|
||||
pkarr_builder
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Set homeserver max record age
|
||||
if let Some(max_record_age) = config.user_max_record_age {
|
||||
builder.max_record_age(Duration::from_secs(max_record_age.get()));
|
||||
}
|
||||
|
||||
let native_client = builder
|
||||
.build()
|
||||
.map_err(|e| JsValue::from_str(&format!("Failed to build client. {}", e)))?;
|
||||
Ok(Self(native_client))
|
||||
}
|
||||
|
||||
/// Create a client with with configurations appropriate for local testing:
|
||||
/// - set Pkarr relays to `["http://localhost:15411"]` instead of default relay.
|
||||
/// - transform `pubky://<pkarr public key>` to `http://<pkarr public key` instead of `https:`
|
||||
/// and read the homeserver HTTP port from the [reserved service parameter key](pubky_common::constants::reserved_param_keys::HTTP_PORT)
|
||||
#[wasm_bindgen]
|
||||
pub fn testnet() -> Self {
|
||||
let mut builder = crate::NativeClient::builder();
|
||||
|
||||
builder.pkarr(|builder| {
|
||||
builder
|
||||
.relays(&TESTNET_RELAYS)
|
||||
.expect("testnet relays are valid urls")
|
||||
});
|
||||
|
||||
let mut client = builder.build().expect("testnet build should be infallible");
|
||||
|
||||
client.testnet = true;
|
||||
|
||||
Self(client)
|
||||
}
|
||||
}
|
||||
13
pubky-client/src/wasm/js_result.rs
Normal file
13
pubky-client/src/wasm/js_result.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
/// Convenient type for functions that return a Err(JsValue).
|
||||
///
|
||||
/// fn method() -> JsResult<T> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
///
|
||||
/// fn method() -> JsResult<T> {
|
||||
/// Err(JsValue::from_str("error"))
|
||||
/// }
|
||||
///
|
||||
pub type JsResult<T> = Result<T, JsValue>;
|
||||
@@ -1,61 +1,9 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod api {
|
||||
pub mod auth;
|
||||
pub mod http;
|
||||
pub mod public;
|
||||
pub mod recovery_file;
|
||||
}
|
||||
|
||||
pub mod wrappers {
|
||||
pub mod keys;
|
||||
pub mod session;
|
||||
}
|
||||
|
||||
static TESTNET_RELAYS: [&str; 1] = ["http://localhost:15411/"];
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Client(crate::NativeClient);
|
||||
|
||||
impl Default for Client {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Client {
|
||||
#[wasm_bindgen(constructor)]
|
||||
/// Create Client with default Settings including default relays
|
||||
pub fn new() -> Self {
|
||||
Self(
|
||||
crate::NativeClient::builder()
|
||||
.build()
|
||||
.expect("building a default NativeClient should be infallible"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a client with with configurations appropriate for local testing:
|
||||
/// - set Pkarr relays to `["http://localhost:15411"]` instead of default relay.
|
||||
/// - transform `pubky://<pkarr public key>` to `http://<pkarr public key` instead of `https:`
|
||||
/// and read the homeserver HTTP port from the [reserved service parameter key](pubky_common::constants::reserved_param_keys::HTTP_PORT)
|
||||
#[wasm_bindgen]
|
||||
pub fn testnet() -> Self {
|
||||
let mut builder = crate::NativeClient::builder();
|
||||
|
||||
builder.pkarr(|builder| {
|
||||
builder
|
||||
.relays(&TESTNET_RELAYS)
|
||||
.expect("testnet relays are valid urls")
|
||||
});
|
||||
|
||||
let mut client = builder.build().expect("testnet build should be infallible");
|
||||
|
||||
client.testnet = true;
|
||||
|
||||
Self(client)
|
||||
}
|
||||
}
|
||||
pub mod api;
|
||||
pub mod constructor;
|
||||
mod js_result;
|
||||
pub mod wrappers;
|
||||
|
||||
#[wasm_bindgen(js_name = "setLogLevel")]
|
||||
pub fn set_log_level(level: &str) -> Result<(), JsValue> {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::wasm::js_result::JsResult;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Keypair(pkarr::Keypair);
|
||||
|
||||
@@ -13,26 +15,18 @@ impl Keypair {
|
||||
|
||||
/// Generate a [Keypair] from a secret key.
|
||||
#[wasm_bindgen(js_name = "fromSecretKey")]
|
||||
pub fn from_secret_key(secret_key: js_sys::Uint8Array) -> Result<Keypair, JsValue> {
|
||||
if !js_sys::Uint8Array::instanceof(&secret_key) {
|
||||
return Err("Expected secret_key to be an instance of Uint8Array".into());
|
||||
}
|
||||
|
||||
let len = secret_key.byte_length();
|
||||
if len != 32 {
|
||||
return Err(format!("Expected secret_key to be 32 bytes, got {len}"))?;
|
||||
}
|
||||
|
||||
let mut bytes = [0; 32];
|
||||
secret_key.copy_to(&mut bytes);
|
||||
|
||||
Ok(Self(pkarr::Keypair::from_secret_key(&bytes)))
|
||||
pub fn from_secret_key(secret_key: Vec<u8>) -> Result<Keypair, JsValue> {
|
||||
let secret_len = secret_key.len();
|
||||
let secret: [u8; 32] = secret_key
|
||||
.try_into()
|
||||
.map_err(|_| format!("Expected secret_key to be 32 bytes, got {}", secret_len))?;
|
||||
Ok(Self(pkarr::Keypair::from_secret_key(&secret)))
|
||||
}
|
||||
|
||||
/// Returns the secret key of this keypair.
|
||||
#[wasm_bindgen(js_name = "secretKey")]
|
||||
pub fn secret_key(&self) -> js_sys::Uint8Array {
|
||||
self.0.secret_key().as_slice().into()
|
||||
pub fn secret_key(&self) -> Vec<u8> {
|
||||
self.0.secret_key().into_iter().collect()
|
||||
}
|
||||
|
||||
/// Returns the [PublicKey] of this keypair.
|
||||
@@ -59,10 +53,16 @@ pub struct PublicKey(pub(crate) pkarr::PublicKey);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl PublicKey {
|
||||
#[wasm_bindgen]
|
||||
/// Convert the PublicKey to Uint8Array
|
||||
pub fn to_uint8array(&self) -> js_sys::Uint8Array {
|
||||
js_sys::Uint8Array::from(self.0.as_bytes().as_slice())
|
||||
/// @deprecated Use `toUint8Array` instead
|
||||
pub fn to_uint8array(&self) -> Vec<u8> {
|
||||
self.0.as_bytes().to_vec()
|
||||
}
|
||||
|
||||
/// Convert the PublicKey to Uint8Array
|
||||
#[wasm_bindgen(js_name = "toUint8Array")]
|
||||
pub fn to_uint8array2(&self) -> Vec<u8> {
|
||||
self.0.as_bytes().to_vec()
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -73,12 +73,8 @@ impl PublicKey {
|
||||
|
||||
#[wasm_bindgen(js_name = "from")]
|
||||
/// @throws
|
||||
pub fn try_from(value: JsValue) -> Result<PublicKey, JsValue> {
|
||||
let string = value
|
||||
.as_string()
|
||||
.ok_or("Couldn't create a PublicKey from this type of value")?;
|
||||
|
||||
Ok(PublicKey(pkarr::PublicKey::try_from(string).map_err(
|
||||
pub fn try_from(value: String) -> JsResult<PublicKey> {
|
||||
Ok(PublicKey(pkarr::PublicKey::try_from(value).map_err(
|
||||
|_| "Couldn't create a PublicKey from this type of value",
|
||||
)?))
|
||||
}
|
||||
|
||||
2
pubky-client/src/wasm/wrappers/mod.rs
Normal file
2
pubky-client/src/wasm/wrappers/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod keys;
|
||||
pub mod session;
|
||||
Reference in New Issue
Block a user