From 32b48d823daaeaa4e0e1ed45c35336da2f64844d Mon Sep 17 00:00:00 2001
From: Jono Wenger <jono@elixxir.io>
Date: Tue, 16 Aug 2022 13:50:33 -0700
Subject: [PATCH] Implement broadcast

---
 bindings/broadcast.go              |  16 ---
 main.go                            |  59 +++++-----
 wasm/broadcast.go                  | 170 +++++++++++++++++++++++++++++
 wasm/broadcast_test.go             |  27 +++++
 {bindings => wasm}/cmix.go         |   6 +-
 {bindings => wasm}/cmix_test.go    |   2 +-
 {bindings => wasm}/connect.go      |   6 +-
 {bindings => wasm}/connect_test.go |   2 +-
 {bindings => wasm}/delivery.go     |   3 +-
 {bindings => wasm}/dummy.go        |   4 +-
 {bindings => wasm}/e2e.go          |   6 +-
 {bindings => wasm}/e2eAuth.go      |  14 ++-
 {bindings => wasm}/e2eHandler.go   |  10 +-
 {bindings => wasm}/e2e_test.go     |   2 +-
 {bindings => wasm}/follow.go       |   5 +-
 {bindings => wasm}/identity.go     |   2 +-
 {bindings => wasm}/logging.go      |   3 +-
 {bindings => wasm}/ndf.go          |   3 +-
 {bindings => wasm}/params.go       |   2 +-
 {bindings => wasm}/secrets.go      |   2 +-
 {bindings => wasm}/utils.go        |   3 +-
 {bindings => wasm}/version.go      |   2 +-
 {bindings => wasm}/wasm_js.s       |   0
 23 files changed, 280 insertions(+), 69 deletions(-)
 delete mode 100644 bindings/broadcast.go
 create mode 100644 wasm/broadcast.go
 create mode 100644 wasm/broadcast_test.go
 rename {bindings => wasm}/cmix.go (97%)
 rename {bindings => wasm}/cmix_test.go (98%)
 rename {bindings => wasm}/connect.go (98%)
 rename {bindings => wasm}/connect_test.go (98%)
 rename {bindings => wasm}/delivery.go (98%)
 rename {bindings => wasm}/dummy.go (99%)
 rename {bindings => wasm}/e2e.go (98%)
 rename {bindings => wasm}/e2eAuth.go (98%)
 rename {bindings => wasm}/e2eHandler.go (98%)
 rename {bindings => wasm}/e2e_test.go (98%)
 rename {bindings => wasm}/follow.go (99%)
 rename {bindings => wasm}/identity.go (99%)
 rename {bindings => wasm}/logging.go (98%)
 rename {bindings => wasm}/ndf.go (97%)
 rename {bindings => wasm}/params.go (99%)
 rename {bindings => wasm}/secrets.go (98%)
 rename {bindings => wasm}/utils.go (98%)
 rename {bindings => wasm}/version.go (98%)
 rename {bindings => wasm}/wasm_js.s (100%)

diff --git a/bindings/broadcast.go b/bindings/broadcast.go
deleted file mode 100644
index 98f85ec6..00000000
--- a/bindings/broadcast.go
+++ /dev/null
@@ -1,16 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 xx network SEZC                                           //
-//                                                                            //
-// Use of this source code is governed by a license that can be found in the  //
-// LICENSE file                                                               //
-////////////////////////////////////////////////////////////////////////////////
-
-package bindings
-
-import (
-	"gitlab.com/elixxir/client/bindings"
-)
-
-type Channel struct {
-	api *bindings.Channel
-}
diff --git a/main.go b/main.go
index 6859b945..2bbdef83 100644
--- a/main.go
+++ b/main.go
@@ -11,10 +11,8 @@ package main
 
 import (
 	"fmt"
-	"gitlab.com/elixxir/xxdk-wasm/bindings"
+	"gitlab.com/elixxir/xxdk-wasm/wasm"
 	"os"
-	"os/signal"
-	"syscall"
 	"syscall/js"
 )
 
@@ -22,64 +20,63 @@ func main() {
 	fmt.Println("Go Web Assembly")
 
 	// wasm/cmix.go
-	js.Global().Set("NewCmix", js.FuncOf(bindings.NewCmix))
-	js.Global().Set("LoadCmix", js.FuncOf(bindings.LoadCmix))
+	js.Global().Set("NewCmix", js.FuncOf(wasm.NewCmix))
+	js.Global().Set("LoadCmix", js.FuncOf(wasm.LoadCmix))
 
 	// wasm/e2e.go
-	js.Global().Set("Login", js.FuncOf(bindings.Login))
-	js.Global().Set("LoginEphemeral", js.FuncOf(bindings.LoginEphemeral))
+	js.Global().Set("Login", js.FuncOf(wasm.Login))
+	js.Global().Set("LoginEphemeral", js.FuncOf(wasm.LoginEphemeral))
 
 	// wasm/identity.go
 	js.Global().Set("StoreReceptionIdentity",
-		js.FuncOf(bindings.StoreReceptionIdentity))
+		js.FuncOf(wasm.StoreReceptionIdentity))
 	js.Global().Set("LoadReceptionIdentity",
-		js.FuncOf(bindings.LoadReceptionIdentity))
+		js.FuncOf(wasm.LoadReceptionIdentity))
 	js.Global().Set("GetIDFromContact",
-		js.FuncOf(bindings.GetIDFromContact))
+		js.FuncOf(wasm.GetIDFromContact))
 	js.Global().Set("GetPubkeyFromContact",
-		js.FuncOf(bindings.GetPubkeyFromContact))
+		js.FuncOf(wasm.GetPubkeyFromContact))
 	js.Global().Set("SetFactsOnContact",
-		js.FuncOf(bindings.SetFactsOnContact))
+		js.FuncOf(wasm.SetFactsOnContact))
 	js.Global().Set("GetFactsFromContact",
-		js.FuncOf(bindings.GetFactsFromContact))
+		js.FuncOf(wasm.GetFactsFromContact))
 
 	// wasm/params.go
 	js.Global().Set("GetDefaultCMixParams",
-		js.FuncOf(bindings.GetDefaultCMixParams))
+		js.FuncOf(wasm.GetDefaultCMixParams))
 	js.Global().Set("GetDefaultE2EParams",
-		js.FuncOf(bindings.GetDefaultE2EParams))
+		js.FuncOf(wasm.GetDefaultE2EParams))
 	js.Global().Set("GetDefaultFileTransferParams",
-		js.FuncOf(bindings.GetDefaultFileTransferParams))
+		js.FuncOf(wasm.GetDefaultFileTransferParams))
 	js.Global().Set("GetDefaultSingleUseParams",
-		js.FuncOf(bindings.GetDefaultSingleUseParams))
+		js.FuncOf(wasm.GetDefaultSingleUseParams))
 	js.Global().Set("GetDefaultE2eFileTransferParams",
-		js.FuncOf(bindings.GetDefaultE2eFileTransferParams))
+		js.FuncOf(wasm.GetDefaultE2eFileTransferParams))
 
 	// wasm/logging.go
-	js.Global().Set("LogLevel", js.FuncOf(bindings.LogLevel))
-	js.Global().Set("RegisterLogWriter", js.FuncOf(bindings.RegisterLogWriter))
-	js.Global().Set("EnableGrpcLogs", js.FuncOf(bindings.EnableGrpcLogs))
+	js.Global().Set("LogLevel", js.FuncOf(wasm.LogLevel))
+	js.Global().Set("RegisterLogWriter", js.FuncOf(wasm.RegisterLogWriter))
+	js.Global().Set("EnableGrpcLogs", js.FuncOf(wasm.EnableGrpcLogs))
 
 	// wasm/ndf.go
 	js.Global().Set("DownloadAndVerifySignedNdfWithUrl",
-		js.FuncOf(bindings.DownloadAndVerifySignedNdfWithUrl))
+		js.FuncOf(wasm.DownloadAndVerifySignedNdfWithUrl))
 
 	// wasm/version.go
-	js.Global().Set("GetVersion", js.FuncOf(bindings.GetVersion))
-	js.Global().Set("GetGitVersion", js.FuncOf(bindings.GetGitVersion))
-	js.Global().Set("GetDependencies", js.FuncOf(bindings.GetDependencies))
+	js.Global().Set("GetVersion", js.FuncOf(wasm.GetVersion))
+	js.Global().Set("GetGitVersion", js.FuncOf(wasm.GetGitVersion))
+	js.Global().Set("GetDependencies", js.FuncOf(wasm.GetDependencies))
 
 	// wasm/secrets.go
-	js.Global().Set("GenerateSecret", js.FuncOf(bindings.GenerateSecret))
+	js.Global().Set("GenerateSecret", js.FuncOf(wasm.GenerateSecret))
 
 	// wasm/dummy.go
 	js.Global().Set("NewDummyTrafficManager",
-		js.FuncOf(bindings.NewDummyTrafficManager))
+		js.FuncOf(wasm.NewDummyTrafficManager))
 
-	// Wait until the user terminates the program
-	c := make(chan os.Signal)
-	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
-	<-c
+	// bindings/broadcast
+	js.Global().Set("NewBroadcastChannel", js.FuncOf(wasm.NewBroadcastChannel))
 
+	<-make(chan bool)
 	os.Exit(0)
 }
diff --git a/wasm/broadcast.go b/wasm/broadcast.go
new file mode 100644
index 00000000..65152f1b
--- /dev/null
+++ b/wasm/broadcast.go
@@ -0,0 +1,170 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                           //
+//                                                                            //
+// Use of this source code is governed by a license that can be found in the  //
+// LICENSE file                                                               //
+////////////////////////////////////////////////////////////////////////////////
+
+//go:build js && wasm
+
+package wasm
+
+import (
+	"gitlab.com/elixxir/client/bindings"
+	"syscall/js"
+)
+
+type Channel struct {
+	api *bindings.Channel
+}
+
+// newE2eJS creates a new Javascript compatible object (map[string]interface{})
+// that matches the E2e structure.
+func newChannelJS(api *bindings.Channel) map[string]interface{} {
+	c := Channel{api}
+	chMap := map[string]interface{}{
+		"Listen":                   c.Listen,
+		"Broadcast":                c.Broadcast,
+		"BroadcastAsymmetric":      c.BroadcastAsymmetric,
+		"MaxPayloadSize":           c.MaxPayloadSize,
+		"MaxAsymmetricPayloadSize": c.MaxAsymmetricPayloadSize,
+		"Get":                      c.Get,
+		"Stop":                     c.Stop,
+	}
+
+	return chMap
+}
+
+// NewBroadcastChannel creates a bindings-layer broadcast channel and starts
+// listening for new messages
+//
+// Parameters:
+//  - args[0] - ID of Cmix object in tracker (int).
+//  - args[1] - JSON of [bindings.ChannelDef] (Uint8Array).
+//
+// Returns:
+//  - Javascript representation of the Channel object.
+//  - Throws a TypeError if creation fails.
+func NewBroadcastChannel(_ js.Value, args []js.Value) interface{} {
+	channelDefinition := CopyBytesToGo(args[1])
+
+	api, err := bindings.NewBroadcastChannel(args[0].Int(), channelDefinition)
+	if err != nil {
+		Throw(TypeError, err.Error())
+		return nil
+	}
+
+	return newChannelJS(api)
+}
+
+// broadcastListener wraps Javascript callbacks to adhere to the
+// [bindings.BroadcastListener] interface.
+type broadcastListener struct {
+	callback func(args ...interface{}) js.Value
+}
+
+func (bl *broadcastListener) Callback(payload []byte, err error) {
+	bl.callback(CopyBytesToJS(payload), err.Error())
+}
+
+// Listen registers a BroadcastListener for a given method. This allows users to
+// handle incoming broadcast messages.
+//
+// Parameters:
+//  - args[0] - Javascript object that has functions that implement the
+//    [bindings.BroadcastListener] interface.
+//  - args[1] - number corresponding to broadcast.Method constant, 0 for
+//    symmetric or 1 for asymmetric (int).
+//
+// Returns:
+//  - Throws a TypeError if registering the listener fails.
+func (c *Channel) Listen(_ js.Value, args []js.Value) interface{} {
+	err := c.api.Listen(&broadcastListener{args[0].Invoke}, args[1].Int())
+	if err != nil {
+		Throw(TypeError, err.Error())
+		return nil
+	}
+
+	return nil
+}
+
+// Broadcast sends a given payload over the broadcast channel using symmetric
+// broadcast.
+//
+// Parameters:
+//  - args[0] - payload (Uint8Array).
+//
+// Returns:
+//  - JSON of [bindings.BroadcastReport], which can be passed into
+//    Cmix.WaitForRoundResult to see if the broadcast succeeded (Uint8Array).
+//  - Throws a TypeError if broadcasting fails.
+func (c *Channel) Broadcast(_ js.Value, args []js.Value) interface{} {
+	report, err := c.api.Broadcast(CopyBytesToGo(args[0]))
+	if err != nil {
+		Throw(TypeError, err.Error())
+		return nil
+	}
+
+	return CopyBytesToJS(report)
+}
+
+// BroadcastAsymmetric sends a given payload over the broadcast channel using
+// asymmetric broadcast. This mode of encryption requires a private key.
+//
+// Parameters:
+//  - args[0] - payload (Uint8Array).
+//  - args[1] - private key (Uint8Array).
+//
+// Returns:
+//  - JSON of [bindings.BroadcastReport], which can be passed into
+//    Cmix.WaitForRoundResult to see if the broadcast succeeded (Uint8Array).
+//  - Throws a TypeError if broadcasting fails.
+func (c *Channel) BroadcastAsymmetric(_ js.Value, args []js.Value) interface{} {
+	report, err := c.api.BroadcastAsymmetric(
+		CopyBytesToGo(args[0]), CopyBytesToGo(args[1]))
+	if err != nil {
+		Throw(TypeError, err.Error())
+		return nil
+	}
+
+	return CopyBytesToJS(report)
+}
+
+// MaxPayloadSize returns the maximum possible payload size which can be
+// broadcast.
+//
+// Returns:
+//  - int
+func (c *Channel) MaxPayloadSize(js.Value, []js.Value) interface{} {
+	return c.api.MaxPayloadSize()
+}
+
+// MaxAsymmetricPayloadSize returns the maximum possible payload size which can
+// be broadcast.
+//
+// Returns:
+//  - int
+func (c *Channel) MaxAsymmetricPayloadSize(js.Value, []js.Value) interface{} {
+	return c.api.MaxAsymmetricPayloadSize()
+}
+
+// Get returns the JSON of the channel definition.
+//
+// Returns:
+//  - JSON of [bindings.ChannelDef] (Uint8Array).
+//  - Throws a TypeError if marshalling fails.
+func (c *Channel) Get(js.Value, []js.Value) interface{} {
+	def, err := c.api.Get()
+	if err != nil {
+		Throw(TypeError, err.Error())
+		return nil
+	}
+
+	return CopyBytesToJS(def)
+}
+
+// Stop stops the channel from listening for more messages.
+func (c *Channel) Stop(js.Value, []js.Value) interface{} {
+	c.api.Stop()
+	return nil
+}
diff --git a/wasm/broadcast_test.go b/wasm/broadcast_test.go
new file mode 100644
index 00000000..39600d7f
--- /dev/null
+++ b/wasm/broadcast_test.go
@@ -0,0 +1,27 @@
+package wasm
+
+import (
+	"gitlab.com/elixxir/client/bindings"
+	"reflect"
+	"testing"
+)
+
+// Tests that the map representing Channel returned by newChannelJS contains
+// all of the methods on Channel.
+func Test_newChannelJS(t *testing.T) {
+	chanType := reflect.TypeOf(&Channel{})
+
+	ch := newChannelJS(&bindings.Channel{})
+	if len(ch) != chanType.NumMethod() {
+		t.Errorf("Channel JS object does not have all methods."+
+			"\nexpected: %d\nreceived: %d", chanType.NumMethod(), len(ch))
+	}
+
+	for i := 0; i < chanType.NumMethod(); i++ {
+		method := chanType.Method(i)
+
+		if _, exists := ch[method.Name]; !exists {
+			t.Errorf("Method %s does not exist.", method.Name)
+		}
+	}
+}
diff --git a/bindings/cmix.go b/wasm/cmix.go
similarity index 97%
rename from bindings/cmix.go
rename to wasm/cmix.go
index 34c8fe96..c27142f6 100644
--- a/bindings/cmix.go
+++ b/wasm/cmix.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -22,8 +22,8 @@ type Cmix struct {
 
 // newCmixJS creates a new Javascript compatible object (map[string]interface{})
 // that matches the Cmix structure.
-func newCmixJS(net *bindings.Cmix) map[string]interface{} {
-	c := Cmix{net}
+func newCmixJS(api *bindings.Cmix) map[string]interface{} {
+	c := Cmix{api}
 	cmix := map[string]interface{}{
 		// cmix.go
 		"GetID": js.FuncOf(c.GetID),
diff --git a/bindings/cmix_test.go b/wasm/cmix_test.go
similarity index 98%
rename from bindings/cmix_test.go
rename to wasm/cmix_test.go
index d6b2c121..06df7c4e 100644
--- a/bindings/cmix_test.go
+++ b/wasm/cmix_test.go
@@ -8,7 +8,7 @@
 //go:build js && wasm
 // +build js,wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/connect.go b/wasm/connect.go
similarity index 98%
rename from bindings/connect.go
rename to wasm/connect.go
index 119b73ca..3d053cf9 100644
--- a/bindings/connect.go
+++ b/wasm/connect.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -64,6 +64,7 @@ func (c *Cmix) Connect(_ js.Value, args []js.Value) interface{} {
 	conn, err := c.api.Connect(args[0].Int(), recipientContact, e2eParamsJSON)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return newConnectJS(conn)
@@ -88,6 +89,7 @@ func (c *Connection) SendE2E(_ js.Value, args []js.Value) interface{} {
 	sendReport, err := c.c.SendE2E(args[0].Int(), CopyBytesToGo(args[1]))
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 	return CopyBytesToJS(sendReport)
 }
@@ -100,6 +102,7 @@ func (c *Connection) Close(js.Value, []js.Value) interface{} {
 	err := c.c.Close()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -137,6 +140,7 @@ func (c *Connection) RegisterListener(_ js.Value, args []js.Value) interface{} {
 		&listener{args[1].Get("Hear").Invoke, args[1].Get("Name").Invoke})
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/connect_test.go b/wasm/connect_test.go
similarity index 98%
rename from bindings/connect_test.go
rename to wasm/connect_test.go
index 79804450..fc0d35e8 100644
--- a/bindings/connect_test.go
+++ b/wasm/connect_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                               //
 ////////////////////////////////////////////////////////////////////////////////
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/delivery.go b/wasm/delivery.go
similarity index 98%
rename from bindings/delivery.go
rename to wasm/delivery.go
index f66f4446..8bf3dcbe 100644
--- a/bindings/delivery.go
+++ b/wasm/delivery.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"syscall/js"
@@ -53,6 +53,7 @@ func (c *Cmix) WaitForRoundResult(_ js.Value, args []js.Value) interface{} {
 	err := c.api.WaitForRoundResult(roundList, mdc, args[2].Int())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/dummy.go b/wasm/dummy.go
similarity index 99%
rename from bindings/dummy.go
rename to wasm/dummy.go
index b538669a..449facb2 100644
--- a/bindings/dummy.go
+++ b/wasm/dummy.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -57,6 +57,7 @@ func NewDummyTrafficManager(_ js.Value, args []js.Value) interface{} {
 		args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return newDummyTrafficJS(dt)
@@ -80,6 +81,7 @@ func (dt *DummyTraffic) SetStatus(_ js.Value, args []js.Value) interface{} {
 	err := dt.api.SetStatus(args[0].Bool())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/e2e.go b/wasm/e2e.go
similarity index 98%
rename from bindings/e2e.go
rename to wasm/e2e.go
index b1016b92..4abdf18b 100644
--- a/bindings/e2e.go
+++ b/wasm/e2e.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -22,8 +22,8 @@ type E2e struct {
 
 // newE2eJS creates a new Javascript compatible object (map[string]interface{})
 // that matches the E2e structure.
-func newE2eJS(newE2E *bindings.E2e) map[string]interface{} {
-	e := E2e{newE2E}
+func newE2eJS(api *bindings.E2e) map[string]interface{} {
+	e := E2e{api}
 	e2e := map[string]interface{}{
 		// e2e.go
 		"GetID":               js.FuncOf(e.GetID),
diff --git a/bindings/e2eAuth.go b/wasm/e2eAuth.go
similarity index 98%
rename from bindings/e2eAuth.go
rename to wasm/e2eAuth.go
index 70f6e19e..5093228d 100644
--- a/bindings/e2eAuth.go
+++ b/wasm/e2eAuth.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"syscall/js"
@@ -44,6 +44,7 @@ func (e *E2e) Request(_ js.Value, args []js.Value) interface{} {
 	rid, err := e.api.Request(partnerContact, factsListJson)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return rid
@@ -76,6 +77,7 @@ func (e *E2e) Confirm(_ js.Value, args []js.Value) interface{} {
 	rid, err := e.api.Confirm(partnerContact)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return rid
@@ -106,6 +108,7 @@ func (e *E2e) Reset(_ js.Value, args []js.Value) interface{} {
 	rid, err := e.api.Reset(partnerContact)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return rid
@@ -130,6 +133,7 @@ func (e *E2e) ReplayConfirm(_ js.Value, args []js.Value) interface{} {
 	rid, err := e.api.ReplayConfirm(partnerContact)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return rid
@@ -154,6 +158,7 @@ func (e *E2e) DeleteRequest(_ js.Value, args []js.Value) interface{} {
 	err := e.api.DeleteRequest(partnerContact)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -167,6 +172,7 @@ func (e *E2e) DeleteAllRequests(js.Value, []js.Value) interface{} {
 	err := e.api.DeleteAllRequests()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -180,6 +186,7 @@ func (e *E2e) DeleteSentRequests(js.Value, []js.Value) interface{} {
 	err := e.api.DeleteSentRequests()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -193,6 +200,7 @@ func (e *E2e) DeleteReceiveRequests(js.Value, []js.Value) interface{} {
 	err := e.api.DeleteReceiveRequests()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -211,6 +219,7 @@ func (e *E2e) GetReceivedRequest(_ js.Value, args []js.Value) interface{} {
 	c, err := e.api.GetReceivedRequest(partnerContact)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return CopyBytesToJS(c)
@@ -233,6 +242,7 @@ func (e *E2e) VerifyOwnership(_ js.Value, args []js.Value) interface{} {
 		receivedContact, verifiedContact, args[2].Int())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return isValid
@@ -254,6 +264,7 @@ func (e *E2e) AddPartnerCallback(_ js.Value, args []js.Value) interface{} {
 	err := e.api.AddPartnerCallback(partnerID, callbacks)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -272,6 +283,7 @@ func (e *E2e) DeletePartnerCallback(_ js.Value, args []js.Value) interface{} {
 	err := e.api.DeletePartnerCallback(partnerID)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/e2eHandler.go b/wasm/e2eHandler.go
similarity index 98%
rename from bindings/e2eHandler.go
rename to wasm/e2eHandler.go
index b57908a1..07d137a0 100644
--- a/bindings/e2eHandler.go
+++ b/wasm/e2eHandler.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"syscall/js"
@@ -31,6 +31,7 @@ func (e *E2e) GetAllPartnerIDs(js.Value, []js.Value) interface{} {
 	partnerIDs, err := e.api.GetAllPartnerIDs()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 	return CopyBytesToJS(partnerIDs)
 }
@@ -83,6 +84,7 @@ func (e *E2e) GetHistoricalDHPrivkey(js.Value, []js.Value) interface{} {
 	privKey, err := e.api.GetHistoricalDHPrivkey()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 	return CopyBytesToJS(privKey)
 }
@@ -97,6 +99,7 @@ func (e *E2e) GetHistoricalDHPubkey(js.Value, []js.Value) interface{} {
 	pubKey, err := e.api.GetHistoricalDHPubkey()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 	return CopyBytesToJS(pubKey)
 }
@@ -114,6 +117,7 @@ func (e *E2e) HasAuthenticatedChannel(_ js.Value, args []js.Value) interface{} {
 	exists, err := e.api.HasAuthenticatedChannel(CopyBytesToGo(args[0]))
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 	return exists
 }
@@ -129,6 +133,7 @@ func (e *E2e) RemoveService(_ js.Value, args []js.Value) interface{} {
 	err := e.api.RemoveService(args[0].String())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -156,6 +161,7 @@ func (e *E2e) SendE2E(_ js.Value, args []js.Value) interface{} {
 		args[0].Int(), recipientId, payload, e2eParams)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return CopyBytesToJS(sendReport)
@@ -200,6 +206,7 @@ func (e *E2e) AddService(_ js.Value, args []js.Value) interface{} {
 	err := e.api.AddService(args[0].String(), p)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -224,6 +231,7 @@ func (e *E2e) RegisterListener(_ js.Value, args []js.Value) interface{} {
 	err := e.api.RegisterListener(recipientId, args[1].Int(), l)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/e2e_test.go b/wasm/e2e_test.go
similarity index 98%
rename from bindings/e2e_test.go
rename to wasm/e2e_test.go
index d0b6fd18..ef6323ac 100644
--- a/bindings/e2e_test.go
+++ b/wasm/e2e_test.go
@@ -8,7 +8,7 @@
 //go:build js && wasm
 // +build js,wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/follow.go b/wasm/follow.go
similarity index 99%
rename from bindings/follow.go
rename to wasm/follow.go
index c00f263a..bd713b14 100644
--- a/bindings/follow.go
+++ b/wasm/follow.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"syscall/js"
@@ -56,6 +56,7 @@ func (c *Cmix) StartNetworkFollower(_ js.Value, args []js.Value) interface{} {
 	err := c.api.StartNetworkFollower(args[0].Int())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -73,6 +74,7 @@ func (c *Cmix) StopNetworkFollower(js.Value, []js.Value) interface{} {
 	err := c.api.StopNetworkFollower()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
@@ -114,6 +116,7 @@ func (c *Cmix) GetNodeRegistrationStatus(js.Value, []js.Value) interface{} {
 	b, err := c.api.GetNodeRegistrationStatus()
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return CopyBytesToJS(b)
diff --git a/bindings/identity.go b/wasm/identity.go
similarity index 99%
rename from bindings/identity.go
rename to wasm/identity.go
index cdc18e5e..eb532493 100644
--- a/bindings/identity.go
+++ b/wasm/identity.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/logging.go b/wasm/logging.go
similarity index 98%
rename from bindings/logging.go
rename to wasm/logging.go
index 82199fb6..b36aae95 100644
--- a/bindings/logging.go
+++ b/wasm/logging.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -38,6 +38,7 @@ func LogLevel(_ js.Value, args []js.Value) interface{} {
 	err := bindings.LogLevel(args[0].Int())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return nil
diff --git a/bindings/ndf.go b/wasm/ndf.go
similarity index 97%
rename from bindings/ndf.go
rename to wasm/ndf.go
index 76d33f01..163f915f 100644
--- a/bindings/ndf.go
+++ b/wasm/ndf.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
@@ -29,6 +29,7 @@ func DownloadAndVerifySignedNdfWithUrl(_ js.Value, args []js.Value) interface{}
 		args[0].String(), args[1].String())
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return nil
 	}
 
 	return CopyBytesToJS(ndf)
diff --git a/bindings/params.go b/wasm/params.go
similarity index 99%
rename from bindings/params.go
rename to wasm/params.go
index c16ce5d1..97dc5d85 100644
--- a/bindings/params.go
+++ b/wasm/params.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/secrets.go b/wasm/secrets.go
similarity index 98%
rename from bindings/secrets.go
rename to wasm/secrets.go
index c1d62731..31be7169 100644
--- a/bindings/secrets.go
+++ b/wasm/secrets.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/utils.go b/wasm/utils.go
similarity index 98%
rename from bindings/utils.go
rename to wasm/utils.go
index 16236e4b..7b0e32df 100644
--- a/bindings/utils.go
+++ b/wasm/utils.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"encoding/json"
@@ -31,6 +31,7 @@ func JsonToJS(src []byte) js.Value {
 	err := json.Unmarshal(src, &inInterface)
 	if err != nil {
 		Throw(TypeError, err.Error())
+		return js.ValueOf(nil)
 	}
 
 	return js.ValueOf(inInterface)
diff --git a/bindings/version.go b/wasm/version.go
similarity index 98%
rename from bindings/version.go
rename to wasm/version.go
index c0a6a0bc..31019233 100644
--- a/bindings/version.go
+++ b/wasm/version.go
@@ -7,7 +7,7 @@
 
 //go:build js && wasm
 
-package bindings
+package wasm
 
 import (
 	"gitlab.com/elixxir/client/bindings"
diff --git a/bindings/wasm_js.s b/wasm/wasm_js.s
similarity index 100%
rename from bindings/wasm_js.s
rename to wasm/wasm_js.s
-- 
GitLab