From 8ae837766200d33f889d1d11a5486f51dacd2ad1 Mon Sep 17 00:00:00 2001 From: Alois Date: Thu, 2 Jul 2026 23:38:38 +0200 Subject: [PATCH] (feat): add auth() function (fix): wasm error --- README.md | 4 +--- example/web-client/src/main.ts | 5 +---- src/sdk/index.ts | 15 +++++++++++++-- wasm/src/client.rs | 16 ++++++++-------- wasm/src/transport.rs | 7 +++++-- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index a5df4d2..265f7b3 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,7 @@ const client = await MTPClient.create({ client.subscribe("SomeType", (message) => console.log(message)); -const clientId = client.credentials?.clientId == null - ? await client.register() - : (await client.connect(), client.credentials.clientId); +const clientId = await client.auth(); await client.send("SomeType", { value: "hello" }); console.log("Connected MTP client", clientId, client.state); diff --git a/example/web-client/src/main.ts b/example/web-client/src/main.ts index 07f24bd..2e8da5c 100644 --- a/example/web-client/src/main.ts +++ b/example/web-client/src/main.ts @@ -199,10 +199,7 @@ async function connect() { log(`Subscribed Pong: ${formatParsedFrame(frame)}`, "received"); }); - const existingClientId = client.credentials?.clientId; - const activeClientId = existingClientId == null - ? await client.register() - : (await client.connect(), BigInt(existingClientId)); + const activeClientId = await client.auth(); clientId = activeClientId; loadKeys(); log(`Connected as client ${activeClientId}`); diff --git a/src/sdk/index.ts b/src/sdk/index.ts index 7006849..3e3d077 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -128,6 +128,7 @@ type NormalizedMTPClientOptions = Omit & { }; const DEFAULT_CREDENTIALS_KEY = "mtp:credentials"; +let wasmInitPromise: Promise>> | undefined; function emit(logger, event) { if (typeof logger === "function") { @@ -394,7 +395,8 @@ export class MTPClient { } static async init(wasm?: MTPClientOptions["wasm"]): Promise>> { - return await initWasm(wasm); + wasmInitPromise ??= initWasm(wasm); + return await wasmInitPromise; } get credentials(): MTPClientCredentials | null { @@ -430,7 +432,7 @@ export class MTPClient { async connect(): Promise { if (this.#credentials?.clientId != null && this.#options.hostPublicKey) { - await this.#connectAuthenticated(); + await this.auth(); return; } @@ -447,6 +449,15 @@ export class MTPClient { } } + async auth(): Promise { + if (!this.#options.hostPublicKey) { + throw new Error("MTPClient.auth requires hostPublicKey"); + } + return this.#credentials?.clientId == null + ? await this.register() + : await this.#connectAuthenticated(); + } + async #connectAuthenticated() { if (!this.#options.hostPublicKey) { throw new Error("MTPClient.connect requires hostPublicKey for authenticated connections"); diff --git a/wasm/src/client.rs b/wasm/src/client.rs index 7aef180..16c33eb 100644 --- a/wasm/src/client.rs +++ b/wasm/src/client.rs @@ -705,19 +705,19 @@ impl WasmClient { let loop_pending_requests = pending_requests.clone(); let ping_timer = self.ping_timer.clone(); wasm_bindgen_futures::spawn_local(async move { - let route_frame = Closure::wrap(Box::new(move |frame: JsValue| { - route_incoming_frame(&frame, &on_msg, &subscriptions, &loop_pending_requests); - }) as Box); loop_transport .receive_loop( - route_frame - .as_ref() - .unchecked_ref::() - .clone(), + move |frame: JsValue| { + route_incoming_frame( + &frame, + &on_msg, + &subscriptions, + &loop_pending_requests, + ); + }, on_err.clone(), ) .await; - drop(route_frame); state.set(ConnectionState::Disconnected); stop_ping_timer(&ping_timer); reject_pending_requests(&pending_requests, "disconnected"); diff --git a/wasm/src/transport.rs b/wasm/src/transport.rs index df59c30..1bdf39c 100644 --- a/wasm/src/transport.rs +++ b/wasm/src/transport.rs @@ -347,12 +347,15 @@ impl WasmTransport { /// Background loop: deliver every incoming frame to `on_message` until the /// connection closes. Shares reader state with `read_one_frame`, so frames /// buffered during the handshake are not lost. - pub async fn receive_loop(&self, on_message: js_sys::Function, on_error: js_sys::Function) { + pub async fn receive_loop(&self, mut on_message: F, on_error: js_sys::Function) + where + F: FnMut(JsValue), + { loop { match self.next_frame().await { Ok(FrameOutcome::Frame(frame)) => match parse_frame_value(&frame) { Ok(parsed) => { - let _ = on_message.call1(&JsValue::NULL, &parsed); + on_message(parsed); } Err(e) => { let message = e.as_string().unwrap_or_else(|| format!("{:?}", e));