Create new enums to type state strings and numbers on server

New enums:
- RegisteredNameFoundState (for NS lookups which emit a RegisteredNameFound signal)
    - This enum is in common/ since it is used by the common LookupResult interface
- NameRegistrationEndedState (for the NameRegistrationEnded signal)
- RegistrationState (for the RegistrationStateChanged signal)
- MessageState (for the AccountMessageStatusChanged signal)
- ConversationMemberEventType (for the ConversationMemberEvent signal)

Other changes:
- Update jamid.ts and jami-signal-interfaces.ts to use these new enums
- Update routers to use the enum members rather than magic constants

GitLab: #89
Change-Id: Ief38df0d4a35c6ecf96375bba01773e60e07b888
diff --git a/server/src/jamid/jami-signal-interfaces.ts b/server/src/jamid/jami-signal-interfaces.ts
index 960034b..851239b 100644
--- a/server/src/jamid/jami-signal-interfaces.ts
+++ b/server/src/jamid/jami-signal-interfaces.ts
@@ -16,8 +16,15 @@
  * <https://www.gnu.org/licenses/>.
  */
 import { AccountDetails, Devices, Message, VolatileDetails } from 'jami-web-common';
+import { RegisteredNameFoundState } from 'jami-web-common';
 
 import { ConversationRequestMetadata } from './conversation-request-metadata.js';
+import {
+  ConversationMemberEventType,
+  MessageState,
+  NameRegistrationEndedState,
+  RegistrationState,
+} from './state-enums.js';
 
 // These interfaces are used to hold all the parameters for signal handlers
 // These parameters' names and types can be found in daemon/bin/nodejs/callback.h
@@ -35,20 +42,20 @@
 
 export interface RegistrationStateChanged {
   accountId: string;
-  state: string;
+  state: RegistrationState;
   code: number;
   details: string;
 }
 
 export interface NameRegistrationEnded {
   accountId: string;
-  state: number;
+  state: NameRegistrationEndedState;
   username: string;
 }
 
 export interface RegisteredNameFound {
   accountId: string;
-  state: number;
+  state: RegisteredNameFoundState;
   address: string;
   username: string;
 }
@@ -68,7 +75,7 @@
   accountId: string;
   messageId: string;
   peer: string;
-  state: number; // TODO: Replace state number with enum (see account_const.h)
+  state: MessageState;
 }
 
 export interface IncomingTrustRequest {
@@ -118,7 +125,7 @@
   accountId: string;
   conversationId: string;
   memberUri: string;
-  event: number;
+  event: ConversationMemberEventType;
 }
 
 export interface MessageReceived {
diff --git a/server/src/jamid/jamid.ts b/server/src/jamid/jamid.ts
index bb47b4e..b6a728b 100644
--- a/server/src/jamid/jamid.ts
+++ b/server/src/jamid/jamid.ts
@@ -25,6 +25,7 @@
   Devices,
   LookupResult,
   Message,
+  RegisteredNameFoundState,
   VolatileDetails,
   WebSocketMessage,
   WebSocketMessageType,
@@ -56,6 +57,12 @@
   VolatileDetailsChanged,
 } from './jami-signal-interfaces.js';
 import { JamiSwig, StringMap, stringMapToRecord, stringVectToArray, vectMapToRecordArray } from './jami-swig.js';
+import {
+  ConversationMemberEventType,
+  MessageState,
+  NameRegistrationEndedState,
+  RegistrationState,
+} from './state-enums.js';
 
 const require = createRequire(import.meta.url);
 
@@ -92,16 +99,20 @@
       onVolatileDetailsChanged.next({ accountId, details });
 
     const onRegistrationStateChanged = new Subject<RegistrationStateChanged>();
-    handlers.RegistrationStateChanged = (accountId: string, state: string, code: number, details: string) =>
+    handlers.RegistrationStateChanged = (accountId: string, state: RegistrationState, code: number, details: string) =>
       onRegistrationStateChanged.next({ accountId, state, code, details });
 
     const onNameRegistrationEnded = new Subject<NameRegistrationEnded>();
-    handlers.NameRegistrationEnded = (accountId: string, state: number, username: string) =>
+    handlers.NameRegistrationEnded = (accountId: string, state: NameRegistrationEndedState, username: string) =>
       onNameRegistrationEnded.next({ accountId, state, username });
 
     const onRegisteredNameFound = new Subject<RegisteredNameFound>();
-    handlers.RegisteredNameFound = (accountId: string, state: number, address: string, username: string) =>
-      onRegisteredNameFound.next({ accountId, state, address, username });
+    handlers.RegisteredNameFound = (
+      accountId: string,
+      state: RegisteredNameFoundState,
+      address: string,
+      username: string
+    ) => onRegisteredNameFound.next({ accountId, state, address, username });
 
     const onKnownDevicesChanged = new Subject<KnownDevicesChanged>();
     handlers.KnownDevicesChanged = (accountId: string, devices: Devices) =>
@@ -112,7 +123,7 @@
       onIncomingAccountMessage.next({ accountId, from, payload });
 
     const onAccountMessageStatusChanged = new Subject<AccountMessageStatusChanged>();
-    handlers.AccountMessageStatusChanged = (accountId: string, messageId: string, peer: string, state: number) =>
+    handlers.AccountMessageStatusChanged = (accountId: string, messageId: string, peer: string, state: MessageState) =>
       onAccountMessageStatusChanged.next({ accountId, messageId, peer, state });
 
     const onContactAdded = new Subject<ContactAdded>();
@@ -147,7 +158,7 @@
       accountId: string,
       conversationId: string,
       memberUri: string,
-      event: number
+      event: ConversationMemberEventType
     ) => {
       onConversationMemberEvent.next({ accountId, conversationId, memberUri, event });
     };
@@ -209,18 +220,18 @@
   async addAccount(accountDetails: Partial<AccountDetails>): Promise<RegistrationStateChanged> {
     accountDetails['Account.type'] = 'RING';
 
-    const detailsStringMap: StringMap = new this.jamiSwig.StringMap();
+    const accountDetailsStringMap: StringMap = new this.jamiSwig.StringMap();
     for (const [key, value] of Object.entries(accountDetails)) {
-      detailsStringMap.set(key, value.toString());
+      accountDetailsStringMap.set(key, value.toString());
     }
 
-    const accountId = this.jamiSwig.addAccount(detailsStringMap);
+    const accountId = this.jamiSwig.addAccount(accountDetailsStringMap);
     return firstValueFrom(
       this.events.onRegistrationStateChanged.pipe(
         filter((value) => value.accountId === accountId),
-        // TODO: is it the only state?
-        // TODO: Replace with string enum in common/
-        filter((value) => value.state === 'REGISTERED' || value.state === 'ERROR_GENERIC')
+        filter(
+          (value) => value.state === RegistrationState.Registered || value.state === RegistrationState.ErrorGeneric
+        )
       )
     );
   }
@@ -242,7 +253,7 @@
   async lookupUsername(username: string, accountId?: string): Promise<LookupResult> {
     const hasRingNs = this.jamiSwig.lookupName(accountId || '', '', username);
     if (!hasRingNs) {
-      throw new Error('Jami does not have NS');
+      throw new Error('Jami does not have a nameserver');
     }
     return firstValueFrom(
       this.events.onRegisteredNameFound.pipe(
@@ -255,7 +266,7 @@
   async lookupAddress(address: string, accountId?: string): Promise<LookupResult> {
     const hasRingNs = this.jamiSwig.lookupAddress(accountId || '', '', address);
     if (!hasRingNs) {
-      throw new Error('Jami does not have NS');
+      throw new Error('Jami does not have a nameserver');
     }
     return firstValueFrom(
       this.events.onRegisteredNameFound.pipe(
@@ -265,11 +276,10 @@
     );
   }
 
-  // TODO: Create enum for state and return that rather than a number
-  async registerUsername(accountId: string, username: string, password: string): Promise<number> {
+  async registerUsername(accountId: string, username: string, password: string): Promise<NameRegistrationEndedState> {
     const hasRingNs = this.jamiSwig.registerName(accountId, password, username);
     if (!hasRingNs) {
-      throw new Error('Jami does not have NS');
+      throw new Error('Jami does not have a nameserver');
     }
     return firstValueFrom(
       this.events.onNameRegistrationEnded.pipe(
@@ -409,10 +419,10 @@
     this.events.onIncomingAccountMessage.subscribe(<T extends WebSocketMessageType>(signal: IncomingAccountMessage) => {
       log.debug('Received IncomingAccountMessage:', JSON.stringify(signal));
 
-      const message: WebSocketMessage<T> = JSON.parse(signal.payload['application/json']);
+      const message: Partial<WebSocketMessage<T>> = JSON.parse(signal.payload['application/json']);
 
-      if (message === undefined) {
-        log.warn('Undefined account message');
+      if (typeof message !== 'object' || message === null) {
+        log.warn('Account message is not an object');
         return;
       }
 
diff --git a/server/src/jamid/state-enums.ts b/server/src/jamid/state-enums.ts
new file mode 100644
index 0000000..08b75da
--- /dev/null
+++ b/server/src/jamid/state-enums.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+export enum RegistrationState {
+  Unregistered = 'UNREGISTERED',
+  Trying = 'TRYING',
+  Registered = 'REGISTERED',
+  ErrorGeneric = 'ERROR_GENERIC',
+  ErrorAuth = 'ERROR_AUTH',
+  ErrorNetwork = 'ERROR_NETWORK',
+  ErrorHost = 'ERROR_HOST',
+  ErrorServiceUnavailable = 'ERROR_SERVICE_UNAVAILABLE',
+  ErrorNeedMigration = 'ERROR_NEED_MIGRATION',
+  Initializing = 'INITIALIZING',
+}
+
+export enum NameRegistrationEndedState {
+  Success,
+  InvalidCredentials,
+  InvalidName,
+  AlreadyTaken,
+  Error,
+}
+
+export enum MessageState {
+  Unknown,
+  Sending,
+  Sent,
+  Displayed,
+  Failure,
+  Cancelled,
+}
+
+export enum ConversationMemberEventType {
+  Add,
+  Join,
+  Remove,
+  Ban,
+  Unban,
+}