From 97234ccc8c4518bf9a4e2ebddf7384b93ec1f13e Mon Sep 17 00:00:00 2001
From: Jono Wenger <jono@elixxir.io>
Date: Mon, 5 Dec 2022 15:20:10 -0800
Subject: [PATCH] Update bindings to match admin command updates

---
 go.mod           |   2 +-
 go.sum           |   4 +-
 wasm/channels.go | 300 +++++++++++++++++++++++++----------------------
 wasm/docs.go     |   2 +
 4 files changed, 164 insertions(+), 144 deletions(-)

diff --git a/go.mod b/go.mod
index 5ea142db..9da6c724 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/hack-pad/go-indexeddb v0.2.0
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/jwalterweatherman v1.1.0
-	gitlab.com/elixxir/client/v4 v4.3.9-0.20221205203130-cceb2467241d
+	gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896
 	gitlab.com/elixxir/crypto v0.0.7-0.20221202020255-46eeab272a7f
 	gitlab.com/elixxir/primitives v0.0.3-0.20221114231218-cc461261a6af
 	gitlab.com/xx_network/crypto v0.0.5-0.20221121220724-8eefdbb0eb46
diff --git a/go.sum b/go.sum
index d31035e8..c92a367c 100644
--- a/go.sum
+++ b/go.sum
@@ -369,8 +369,8 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
 github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40=
 gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221205203130-cceb2467241d h1:AGrBjrjhI6+Vef9Cw3MswBkcVer8G/hpQYuOHzNOgnU=
-gitlab.com/elixxir/client/v4 v4.3.9-0.20221205203130-cceb2467241d/go.mod h1:6zBHVEOwB42N3Ba3879GW0huu595RLSar04KlNsa7QE=
+gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896 h1:I/72gteNvOzH1ipt2QxmyQZ8xRrmZHm4yMwffl5T0RY=
+gitlab.com/elixxir/client/v4 v4.3.9-0.20221205230100-8d476bdbd896/go.mod h1:6zBHVEOwB42N3Ba3879GW0huu595RLSar04KlNsa7QE=
 gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4 h1:bLRjVCyMVde4n2hTVgoyyIAWrKI4CevpChchkPeb6A0=
 gitlab.com/elixxir/comms v0.0.4-0.20221110181420-84bca6216fe4/go.mod h1:XhI2/CMng+xcH3mAs+1aPz29PSNu1079XMJ8V+xxihw=
 gitlab.com/elixxir/crypto v0.0.7-0.20221202020255-46eeab272a7f h1:e7h3InxgzRnYOqgUgHrTfK6CW8qNM2SiYRj9tOvsFjA=
diff --git a/wasm/channels.go b/wasm/channels.go
index 9d98db35..6f733d66 100644
--- a/wasm/channels.go
+++ b/wasm/channels.go
@@ -64,6 +64,11 @@ func newChannelsManagerJS(api *bindings.ChannelsManager) map[string]any {
 		"DeleteNickname":        js.FuncOf(cm.DeleteNickname),
 		"GetNickname":           js.FuncOf(cm.GetNickname),
 		"Muted":                 js.FuncOf(cm.Muted),
+		"IsChannelAdmin":        js.FuncOf(cm.IsChannelAdmin),
+		"ExportChannelAdminKey": js.FuncOf(cm.ExportChannelAdminKey),
+		"VerifyChannelAdminKey": js.FuncOf(cm.VerifyChannelAdminKey),
+		"ImportChannelAdminKey": js.FuncOf(cm.ImportChannelAdminKey),
+		"DeleteChannelAdminKey": js.FuncOf(cm.DeleteChannelAdminKey),
 
 		// Channel Receiving Logic and Callback Registration
 		"RegisterReceiveHandler": js.FuncOf(cm.RegisterReceiveHandler),
@@ -227,28 +232,6 @@ func GetPublicChannelIdentityFromPrivate(_ js.Value, args []js.Value) any {
 	return utils.CopyBytesToJS(identity)
 }
 
-// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
-type eventModelBuilder struct {
-	build func(args ...any) js.Value
-}
-
-// Build initializes and returns the event model.  It wraps a Javascript object
-// that has all the methods in [bindings.EventModel] to make it adhere to the Go
-// interface [bindings.EventModel].
-func (emb *eventModelBuilder) Build(path string) bindings.EventModel {
-	emJs := emb.build(path)
-	return &eventModel{
-		joinChannel:         utils.WrapCB(emJs, "JoinChannel"),
-		leaveChannel:        utils.WrapCB(emJs, "LeaveChannel"),
-		receiveMessage:      utils.WrapCB(emJs, "ReceiveMessage"),
-		receiveReply:        utils.WrapCB(emJs, "ReceiveReply"),
-		receiveReaction:     utils.WrapCB(emJs, "ReceiveReaction"),
-		updateFromUUID:      utils.WrapCB(emJs, "UpdateFromUUID"),
-		updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"),
-		getMessage:          utils.WrapCB(emJs, "GetMessage"),
-	}
-}
-
 // NewChannelsManager creates a new [ChannelsManager] from a new private
 // identity ([channel.PrivateIdentity]).
 //
@@ -517,6 +500,10 @@ func loadChannelsManagerWithIndexedDb(cmixID int, storageTag string,
 	return utils.CreatePromise(promiseFn)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Channel Actions                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
 // DecodePublicURL decodes the channel URL into a channel pretty print. This
 // function can only be used for public channel URLs. To get the privacy level
 // of a channel URL, use [GetShareUrlType].
@@ -628,9 +615,8 @@ func GetChannelInfo(_ js.Value, args []js.Value) any {
 //     optional but cannot be longer than 144 characters and can include all
 //     Unicode characters. It cannot be changed once a channel is created.
 //   - args[2] - The [broadcast.PrivacyLevel] of the channel (int). 0 = public,
-//
-// //     1 = private, and 2 = secret. Refer to the comment below for more
-// //     information.
+//     1 = private, and 2 = secret. Refer to the comment below for more
+//     information.
 //
 // Returns:
 //   - The pretty print of the channel (string).
@@ -681,28 +667,6 @@ func (cm *ChannelsManager) JoinChannel(_ js.Value, args []js.Value) any {
 	return utils.CopyBytesToJS(ci)
 }
 
-// GetChannels returns the IDs of all channels that have been joined.
-//
-// Returns:
-//   - JSON of an array of marshalled [id.ID] (Uint8Array).
-//   - Throws a TypeError if getting the channels fails.
-//
-// JSON Example:
-//
-//	{
-//	  "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
-//	  "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD"
-//	}
-func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any {
-	channelList, err := cm.api.GetChannels()
-	if err != nil {
-		utils.Throw(utils.TypeError, err)
-		return nil
-	}
-
-	return utils.CopyBytesToJS(channelList)
-}
-
 // LeaveChannel leaves the given channel. It will return an error if the channel
 // was not previously joined.
 //
@@ -743,6 +707,28 @@ func (cm *ChannelsManager) ReplayChannel(_ js.Value, args []js.Value) any {
 	return nil
 }
 
+// GetChannels returns the IDs of all channels that have been joined.
+//
+// Returns:
+//   - JSON of an array of marshalled [id.ID] (Uint8Array).
+//   - Throws a TypeError if getting the channels fails.
+//
+// JSON Example:
+//
+//	{
+//	  "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID",
+//	  "15tNdkKbYXoMn58NO6VbDMDWFEyIhTWEGsvgcJsHWAgD"
+//	}
+func (cm *ChannelsManager) GetChannels(js.Value, []js.Value) any {
+	channelList, err := cm.api.GetChannels()
+	if err != nil {
+		utils.Throw(utils.TypeError, err)
+		return nil
+	}
+
+	return utils.CopyBytesToJS(channelList)
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Channel Share URL                                                          //
 ////////////////////////////////////////////////////////////////////////////////
@@ -870,50 +856,6 @@ func (cm *ChannelsManager) SendGeneric(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
-// SendAdminGeneric is used to send a raw message over a channel encrypted with
-// admin keys, identifying it as sent by the admin. In general, it should be
-// wrapped in a function that defines the wire protocol. If the final message,
-// before being sent over the wire, is too long, this will return an error. The
-// message must be at most 510 bytes long.
-//
-// Parameters:
-//   - args[0] - The PEM-encode admin RSA private key (Uint8Array).
-//   - args[1] - Marshalled bytes of the channel [id.ID] (Uint8Array).
-//   - args[2] - The message type of the message. This will be a valid
-//     [channels.MessageType] (int).
-//   - args[3] - The contents of the message (Uint8Array).
-//   - args[4] - The lease of the message. This will be how long the message is
-//     valid until, in milliseconds. As per the [channels.Manager]
-//     documentation, this has different meanings depending on the use case.
-//     These use cases may be generic enough that they will not be enumerated
-//     here (int).
-//   - args[5] - JSON of [xxdk.CMIXParams]. If left empty
-//     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
-//
-// Returns a promise:
-//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
-//   - Rejected with an error if sending fails.
-func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
-	adminPrivateKey := utils.CopyBytesToGo(args[0])
-	marshalledChanId := utils.CopyBytesToGo(args[1])
-	messageType := args[2].Int()
-	message := utils.CopyBytesToGo(args[3])
-	leaseTimeMS := int64(args[4].Int())
-	cmixParamsJSON := utils.CopyBytesToGo(args[5])
-
-	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := cm.api.SendAdminGeneric(adminPrivateKey,
-			marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON)
-		if err != nil {
-			reject(utils.JsTrace(err))
-		} else {
-			resolve(utils.CopyBytesToJS(sendReport))
-		}
-	}
-
-	return utils.CreatePromise(promiseFn)
-}
-
 // SendMessage is used to send a formatted message over a channel.
 // Due to the underlying encoding using compression, it isn't possible to define
 // the largest payload that can be sent, but it will always be possible to send
@@ -1045,38 +987,89 @@ func (cm *ChannelsManager) SendReaction(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Admin Sending                                                              //
+////////////////////////////////////////////////////////////////////////////////
+
+// SendAdminGeneric is used to send a raw message over a channel encrypted with
+// admin keys, identifying it as sent by the admin. In general, it should be
+// wrapped in a function that defines the wire protocol.
+//
+// If the final message, before being sent over the wire, is too long, this will
+// return an error. The message must be at most 510 bytes long.
+//
+// If the user is not an admin of the channel (i.e. does not have a private key
+// for the channel saved to storage), then the error [channels.NotAnAdminErr] is
+// returned.
+//
+// Parameters:
+//   - args[0] - Marshalled bytes of the channel [id.ID] (Uint8Array).
+//   - args[1] - The message type of the message. This will be a valid
+//     [channels.MessageType] (int).
+//   - args[2] - The contents of the message (Uint8Array). The message should be
+//     at most 510 bytes.
+//   - args[3] - The lease of the message. This will be how long the message is
+//     valid until, in milliseconds. As per the [channels.Manager]
+//     documentation, this has different meanings depending on the use case.
+//     These use cases may be generic enough that they will not be enumerated
+//     here (int).
+//   - args[4] - JSON of [xxdk.CMIXParams]. If left empty
+//     [bindings.GetDefaultCMixParams] will be used internally (Uint8Array).
+//
+// Returns a promise:
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
+func (cm *ChannelsManager) SendAdminGeneric(_ js.Value, args []js.Value) any {
+	marshalledChanId := utils.CopyBytesToGo(args[0])
+	messageType := args[1].Int()
+	message := utils.CopyBytesToGo(args[2])
+	leaseTimeMS := int64(args[3].Int())
+	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+
+	promiseFn := func(resolve, reject func(args ...any) js.Value) {
+		sendReport, err := cm.api.SendAdminGeneric(
+			marshalledChanId, messageType, message, leaseTimeMS, cmixParamsJSON)
+		if err != nil {
+			reject(utils.JsTrace(err))
+		} else {
+			resolve(utils.CopyBytesToJS(sendReport))
+		}
+	}
+
+	return utils.CreatePromise(promiseFn)
+}
+
 // DeleteMessage deletes the targeted message from user's view. Users may delete
-// their own messages (by leaving the private key as nil) but only the channel
-// admin can delete other user's messages.
+// their own messages but only the channel admin can delete other user's
+// messages. If the user is not an admin of the channel or if they are not the
+// sender of the targetMessage, then the error [channels.NotAnAdminErr] is
+// returned.
 //
 // If undoAction is true, then the targeted message is un-deleted.
 //
-// Clients will drop the deletion if they do not recognize the target message.
+// Clients will drop the deletion if they do not recognize the target
+// message.
 //
 // Parameters:
-//   - args[0] - The PEM-encoded admin RSA private key for the channel
-//     (Uint8Array). If a user is trying to delete their own message, make this
-//     empty.
-//   - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array).
-//   - args[2] - The marshalled [channel.MessageID] of the message you want to
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The marshalled [channel.MessageID] of the message you want to
 //     delete (Uint8Array).
-//   - args[3] - Set to true to un-delete the message (boolean).
-//   - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//   - args[2] - Set to true to un-delete the message (boolean).
+//   - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and
 //     [GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns:
 //   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
 //   - Rejected with an error if sending fails.
 func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any {
-	adminPrivateKey := utils.CopyBytesToGo(args[0])
-	channelIdBytes := utils.CopyBytesToGo(args[1])
-	targetMessageIdBytes := utils.CopyBytesToGo(args[2])
-	undoAction := args[3].Bool()
-	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	targetMessageIdBytes := utils.CopyBytesToGo(args[1])
+	undoAction := args[2].Bool()
+	cmixParamsJSON := utils.CopyBytesToGo(args[3])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := cm.api.DeleteMessage(adminPrivateKey, channelIdBytes,
-			targetMessageIdBytes, undoAction, cmixParamsJSON)
+		sendReport, err := cm.api.DeleteMessage(
+			channelIdBytes, targetMessageIdBytes, undoAction, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -1087,35 +1080,35 @@ func (cm *ChannelsManager) DeleteMessage(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
-// PinMessage pins the target message to the top of a channel view for all users
-// in the specified channel. Only the channel admin can pin user messages.
+// PinMessage pins the target message to the top of a channel view for all
+// users in the specified channel. Only the channel admin can pin user
+// messages; if the user is not an admin of the channel, then the error
+// [channels.NotAnAdminErr] is returned.
 //
 // If undoAction is true, then the targeted message is unpinned.
 //
 // Clients will drop the pin if they do not recognize the target message.
 //
 // Parameters:
-//   - args[0] - The PEM-encoded admin RSA private key for the channel
-//     (Uint8Array).
-//   - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array).
-//   - args[2] - The marshalled [channel.MessageID] of the message you want to
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The marshalled [channel.MessageID] of the message you want to
 //     pin (Uint8Array).
-//   - args[3] - Set to true to unpin the message (boolean).
-//   - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//   - args[2] - Set to true to unpin the message (boolean).
+//   - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and
 //     [GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns:
-//   - []byte - JSON of [ChannelSendReport].
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
 func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any {
-	adminPrivateKey := utils.CopyBytesToGo(args[0])
-	channelIdBytes := utils.CopyBytesToGo(args[1])
-	targetMessageIdBytes := utils.CopyBytesToGo(args[2])
-	undoAction := args[3].Bool()
-	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	targetMessageIdBytes := utils.CopyBytesToGo(args[1])
+	undoAction := args[2].Bool()
+	cmixParamsJSON := utils.CopyBytesToGo(args[3])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := cm.api.PinMessage(adminPrivateKey, channelIdBytes,
-			targetMessageIdBytes, undoAction, cmixParamsJSON)
+		sendReport, err := cm.api.PinMessage(
+			channelIdBytes, targetMessageIdBytes, undoAction, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -1128,32 +1121,32 @@ func (cm *ChannelsManager) PinMessage(_ js.Value, args []js.Value) any {
 
 // MuteUser is used to mute a user in a channel. Muting a user will cause all
 // future messages from the user being hidden from view. Muted users are also
-// unable to send messages. Only the channel admin can mute a user.
+// unable to send messages. Only the channel admin can mute a user; if the user
+// is not an admin of the channel, then the error [channels.NotAnAdminErr] is
+// returned.
 //
 // If undoAction is true, then the targeted user will be unmuted.
 //
 // Parameters:
-//   - args[0] - The PEM-encoded admin RSA private key for the channel
+//   - args[0] - Marshalled bytes of channel [id.ID] (Uint8Array).
+//   - args[1] - The [ed25519.PublicKey] of the user you want to mute
 //     (Uint8Array).
-//   - args[1] - Marshalled bytes of channel [id.ID] (Uint8Array).
-//   - mutedUserPubKeyBytes - The [ed25519.PublicKey] of the user you want to
-//     mute.
-//   - args[3] - Set to true to unmute the message (boolean).
-//   - args[4] - JSON of [xxdk.CMIXParams]. This may be empty, and
+//   - args[2] - Set to true to unmute the message (boolean).
+//   - args[3] - JSON of [xxdk.CMIXParams]. This may be empty, and
 //     [GetDefaultCMixParams] will be used internally (Uint8Array).
 //
 // Returns:
-//   - []byte - JSON of [ChannelSendReport].
+//   - Resolves to the JSON of [bindings.ChannelSendReport] (Uint8Array).
+//   - Rejected with an error if sending fails.
 func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any {
-	adminPrivateKey := utils.CopyBytesToGo(args[0])
-	channelIdBytes := utils.CopyBytesToGo(args[1])
-	mutedUserPubKeyBytes := utils.CopyBytesToGo(args[2])
-	undoAction := args[3].Bool()
-	cmixParamsJSON := utils.CopyBytesToGo(args[4])
+	channelIdBytes := utils.CopyBytesToGo(args[0])
+	mutedUserPubKeyBytes := utils.CopyBytesToGo(args[1])
+	undoAction := args[2].Bool()
+	cmixParamsJSON := utils.CopyBytesToGo(args[3])
 
 	promiseFn := func(resolve, reject func(args ...any) js.Value) {
-		sendReport, err := cm.api.MuteUser(adminPrivateKey, channelIdBytes,
-			mutedUserPubKeyBytes, undoAction, cmixParamsJSON)
+		sendReport, err := cm.api.MuteUser(
+			channelIdBytes, mutedUserPubKeyBytes, undoAction, cmixParamsJSON)
 		if err != nil {
 			reject(utils.JsTrace(err))
 		} else {
@@ -1164,6 +1157,10 @@ func (cm *ChannelsManager) MuteUser(_ js.Value, args []js.Value) any {
 	return utils.CreatePromise(promiseFn)
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// Other Channel Actions                                                      //
+////////////////////////////////////////////////////////////////////////////////
+
 // GetIdentity returns the marshaled public identity ([channel.Identity]) that
 // the channel is using.
 //
@@ -1500,6 +1497,28 @@ func (cm *ChannelsManager) RegisterReceiveHandler(_ js.Value, args []js.Value) a
 // Event Model Logic                                                          //
 ////////////////////////////////////////////////////////////////////////////////
 
+// eventModelBuilder adheres to the [bindings.EventModelBuilder] interface.
+type eventModelBuilder struct {
+	build func(args ...any) js.Value
+}
+
+// Build initializes and returns the event model.  It wraps a Javascript object
+// that has all the methods in [bindings.EventModel] to make it adhere to the Go
+// interface [bindings.EventModel].
+func (emb *eventModelBuilder) Build(path string) bindings.EventModel {
+	emJs := emb.build(path)
+	return &eventModel{
+		joinChannel:         utils.WrapCB(emJs, "JoinChannel"),
+		leaveChannel:        utils.WrapCB(emJs, "LeaveChannel"),
+		receiveMessage:      utils.WrapCB(emJs, "ReceiveMessage"),
+		receiveReply:        utils.WrapCB(emJs, "ReceiveReply"),
+		receiveReaction:     utils.WrapCB(emJs, "ReceiveReaction"),
+		updateFromUUID:      utils.WrapCB(emJs, "UpdateFromUUID"),
+		updateFromMessageID: utils.WrapCB(emJs, "UpdateFromMessageID"),
+		getMessage:          utils.WrapCB(emJs, "GetMessage"),
+	}
+}
+
 // eventModel wraps Javascript callbacks to adhere to the [bindings.EventModel]
 // interface.
 type eventModel struct {
@@ -1862,8 +1881,7 @@ func (c *ChannelDbCipher) MarshalJSON(js.Value, []js.Value) any {
 	return utils.CopyBytesToJS(data)
 }
 
-// UnmarshalJSON unmarshalls JSON into the cipher. This function adheres to the
-// json.Unmarshaler interface.
+// UnmarshalJSON unmarshalls JSON into the cipher.
 //
 // Note that this function does not transfer the internal RNG. Use
 // [channel.NewCipherFromJSON] to properly reconstruct a cipher from JSON.
diff --git a/wasm/docs.go b/wasm/docs.go
index 33b0d56e..5e0466b5 100644
--- a/wasm/docs.go
+++ b/wasm/docs.go
@@ -10,6 +10,7 @@
 package wasm
 
 import (
+	"crypto/ed25519"
 	"github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/v4/auth"
 	"gitlab.com/elixxir/client/v4/catalog"
@@ -67,4 +68,5 @@ var (
 	_ = broadcast.PrivacyLevel(0)
 	_ = broadcast.Channel{}
 	_ = netTime.Now
+	_ = ed25519.PublicKey{}
 )
-- 
GitLab