diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
index 4900e8315..be24b25ec 100644
--- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
@@ -1,219 +1,227 @@
 #pragma once
 
 #include "../CryptoTools/Persist.h"
 #include "entities/AuxUserInfo.h"
 #include "entities/CommunityInfo.h"
+#include "entities/DMOperation.h"
 #include "entities/Draft.h"
 #include "entities/EntryInfo.h"
 #include "entities/InboundP2PMessage.h"
 #include "entities/IntegrityThreadHash.h"
 #include "entities/KeyserverInfo.h"
 #include "entities/LocalMessageInfo.h"
 #include "entities/Media.h"
 #include "entities/Message.h"
 #include "entities/MessageStoreThread.h"
 #include "entities/OlmPersistAccount.h"
 #include "entities/OlmPersistSession.h"
 #include "entities/OutboundP2PMessage.h"
 #include "entities/PersistItem.h"
 #include "entities/Report.h"
 #include "entities/SyncedMetadataEntry.h"
 #include "entities/Thread.h"
 #include "entities/ThreadActivityEntry.h"
 #include "entities/UserInfo.h"
 
 #include <string>
 
 namespace comm {
 
 /**
  * if any initialization/cleaning up steps are required for specific
  * database managers they should appear in constructors/destructors
  * following the RAII pattern
  */
 class DatabaseQueryExecutor {
 public:
   virtual std::string getDraft(std::string key) const = 0;
   virtual std::unique_ptr<Thread> getThread(std::string threadID) const = 0;
   virtual void updateDraft(std::string key, std::string text) const = 0;
   virtual bool moveDraft(std::string oldKey, std::string newKey) const = 0;
   virtual std::vector<Draft> getAllDrafts() const = 0;
   virtual void removeAllDrafts() const = 0;
   virtual void removeDrafts(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllMessages() const = 0;
   virtual std::vector<MessageEntity> getInitialMessages() const = 0;
   virtual std::vector<MessageEntity>
   fetchMessages(std::string threadID, int limit, int offset) const = 0;
   virtual void removeMessages(const std::vector<std::string> &ids) const = 0;
   virtual void
   removeMessagesForThreads(const std::vector<std::string> &threadIDs) const = 0;
   virtual void replaceMessage(const Message &message) const = 0;
   virtual void rekeyMessage(std::string from, std::string to) const = 0;
   virtual void removeAllMedia() const = 0;
   virtual void replaceMessageStoreThreads(
       const std::vector<MessageStoreThread> &threads) const = 0;
   virtual void
   removeMessageStoreThreads(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllMessageStoreThreads() const = 0;
   virtual std::vector<MessageStoreThread> getAllMessageStoreThreads() const = 0;
   virtual void
   removeMediaForMessages(const std::vector<std::string> &msgIDs) const = 0;
   virtual void removeMediaForMessage(std::string msgID) const = 0;
   virtual void
   removeMediaForThreads(const std::vector<std::string> &threadIDs) const = 0;
   virtual void replaceMedia(const Media &media) const = 0;
   virtual void rekeyMediaContainers(std::string from, std::string to) const = 0;
   virtual std::vector<Thread> getAllThreads() const = 0;
   virtual void removeThreads(std::vector<std::string> ids) const = 0;
   virtual void replaceThread(const Thread &thread) const = 0;
   virtual void removeAllThreads() const = 0;
   virtual void replaceReport(const Report &report) const = 0;
   virtual void removeReports(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllReports() const = 0;
   virtual std::vector<Report> getAllReports() const = 0;
   virtual void
   setPersistStorageItem(std::string key, std::string item) const = 0;
   virtual void removePersistStorageItem(std::string key) const = 0;
   virtual std::string getPersistStorageItem(std::string key) const = 0;
   virtual void replaceUser(const UserInfo &userInfo) const = 0;
   virtual void removeUsers(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllUsers() const = 0;
   virtual std::vector<UserInfo> getAllUsers() const = 0;
   virtual void replaceKeyserver(const KeyserverInfo &keyserverInfo) const = 0;
   virtual void removeKeyservers(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllKeyservers() const = 0;
   virtual std::vector<KeyserverInfo> getAllKeyservers() const = 0;
   virtual void replaceCommunity(const CommunityInfo &communityInfo) const = 0;
   virtual void removeCommunities(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllCommunities() const = 0;
   virtual std::vector<CommunityInfo> getAllCommunities() const = 0;
   virtual void replaceIntegrityThreadHashes(
       const std::vector<IntegrityThreadHash> &threadHashes) const = 0;
   virtual void
   removeIntegrityThreadHashes(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllIntegrityThreadHashes() const = 0;
   virtual std::vector<IntegrityThreadHash>
   getAllIntegrityThreadHashes() const = 0;
   virtual void replaceSyncedMetadataEntry(
       const SyncedMetadataEntry &syncedMetadataEntry) const = 0;
   virtual void
   removeSyncedMetadata(const std::vector<std::string> &names) const = 0;
   virtual void removeAllSyncedMetadata() const = 0;
   virtual std::vector<SyncedMetadataEntry> getAllSyncedMetadata() const = 0;
   virtual void replaceAuxUserInfo(const AuxUserInfo &userInfo) const = 0;
   virtual void
   removeAuxUserInfos(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllAuxUserInfos() const = 0;
   virtual std::vector<AuxUserInfo> getAllAuxUserInfos() const = 0;
   virtual void replaceThreadActivityEntry(
       const ThreadActivityEntry &threadActivityEntry) const = 0;
   virtual void
   removeThreadActivityEntries(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllThreadActivityEntries() const = 0;
   virtual std::vector<ThreadActivityEntry>
   getAllThreadActivityEntries() const = 0;
   virtual void replaceEntry(const EntryInfo &entryInfo) const = 0;
   virtual void removeEntries(const std::vector<std::string> &ids) const = 0;
   virtual void removeAllEntries() const = 0;
   virtual std::vector<EntryInfo> getAllEntries() const = 0;
   virtual void replaceMessageStoreLocalMessageInfo(
       const LocalMessageInfo &localMessageInfo) const = 0;
   virtual void removeMessageStoreLocalMessageInfos(
       const std::vector<std::string> &ids) const = 0;
   virtual void removeAllMessageStoreLocalMessageInfos() const = 0;
   virtual std::vector<LocalMessageInfo>
   getAllMessageStoreLocalMessageInfos() const = 0;
   virtual void beginTransaction() const = 0;
   virtual void commitTransaction() const = 0;
   virtual void rollbackTransaction() const = 0;
   virtual int getContentAccountID() const = 0;
   virtual int getNotifsAccountID() const = 0;
   virtual std::vector<OlmPersistSession> getOlmPersistSessionsData() const = 0;
   virtual std::optional<std::string>
   getOlmPersistAccountData(int accountID) const = 0;
   virtual void
   storeOlmPersistSession(const OlmPersistSession &session) const = 0;
   virtual void storeOlmPersistAccount(
       int accountID,
       const std::string &accountData) const = 0;
   virtual void
   storeOlmPersistData(int accountID, crypto::Persist persist) const = 0;
   virtual void setNotifyToken(std::string token) const = 0;
   virtual void clearNotifyToken() const = 0;
   virtual void stampSQLiteDBUserID(std::string userID) const = 0;
   virtual std::string getSQLiteStampedUserID() const = 0;
   virtual void setMetadata(std::string entryName, std::string data) const = 0;
   virtual void clearMetadata(std::string entryName) const = 0;
   virtual std::string getMetadata(std::string entryName) const = 0;
   virtual void restoreFromMainCompaction(
       std::string mainCompactionPath,
       std::string mainCompactionEncryptionKey,
       std::string maxVersion) const = 0;
   virtual void
   restoreFromBackupLog(const std::vector<std::uint8_t> &backupLog) const = 0;
   virtual void addOutboundP2PMessages(
       const std::vector<OutboundP2PMessage> &messages) const = 0;
   virtual std::vector<OutboundP2PMessage>
   getOutboundP2PMessagesByID(const std::vector<std::string> &ids) const = 0;
   virtual std::vector<OutboundP2PMessage>
   getUnsentOutboundP2PMessages() const = 0;
   virtual void removeOutboundP2PMessage(
       std::string confirmedMessageID,
       std::string deviceID) const = 0;
   virtual void
   removeAllOutboundP2PMessages(const std::string &deviceID) const = 0;
   virtual void setCiphertextForOutboundP2PMessage(
       std::string messageID,
       std::string deviceID,
       std::string ciphertext) const = 0;
   virtual void markOutboundP2PMessageAsSent(
       std::string messageID,
       std::string deviceID) const = 0;
   virtual std::vector<std::string>
   resetOutboundP2PMessagesForDevice(std::string deviceID) const = 0;
   virtual void addInboundP2PMessage(InboundP2PMessage message) const = 0;
   virtual std::vector<InboundP2PMessage> getAllInboundP2PMessage() const = 0;
   virtual void
   removeInboundP2PMessages(const std::vector<std::string> &ids) const = 0;
   virtual std::vector<InboundP2PMessage>
   getInboundP2PMessagesByID(const std::vector<std::string> &ids) const = 0;
   virtual std::vector<MessageEntity>
   getRelatedMessages(const std::string &messageID) const = 0;
   virtual void updateMessageSearchIndex(
       std::string originalMessageID,
       std::string messageID,
       std::string processedContent) const = 0;
   virtual std::vector<MessageEntity> searchMessages(
       std::string query,
       std::string threadID,
       std::optional<std::string> timestampCursor,
       std::optional<std::string> messageIDCursor) const = 0;
   virtual std::vector<MessageEntity> getRelatedMessagesForSearch(
       const std::vector<std::string> &messageIDs) const = 0;
+  virtual void replaceDMOperation(const DMOperation &operation) const = 0;
+  virtual void removeAllDMOperations() const = 0;
+  virtual void
+  removeDMOperations(const std::vector<std::string> &ids) const = 0;
+  virtual std::vector<DMOperation> getDMOperations() const = 0;
+  virtual std::vector<DMOperation>
+  getDMOperationsByType(const std::string &operationType) const = 0;
   virtual ~DatabaseQueryExecutor() = default;
 
 #ifdef EMSCRIPTEN
   virtual std::vector<WebThread> getAllThreadsWeb() const = 0;
   virtual void replaceThreadWeb(const WebThread &thread) const = 0;
   virtual std::vector<MessageWithMedias> getInitialMessagesWeb() const = 0;
   virtual std::vector<MessageWithMedias>
   fetchMessagesWeb(std::string threadID, int limit, int offset) const = 0;
   virtual void replaceMessageWeb(const WebMessage &message) const = 0;
   virtual NullableString getOlmPersistAccountDataWeb(int accountID) const = 0;
   virtual std::vector<MessageWithMedias>
   getRelatedMessagesWeb(const std::string &messageID) const = 0;
   virtual std::vector<MessageWithMedias> searchMessagesWeb(
       std::string query,
       std::string threadID,
       std::optional<std::string> timestampCursor,
       std::optional<std::string> messageIDCursor) const = 0;
 #else
   virtual void createMainCompaction(std::string backupID) const = 0;
   virtual void captureBackupLogs() const = 0;
   virtual void setUserDataKeys(
       const std::string &backupDataKey,
       const std::string &backupLogDataKey) const = 0;
 #endif
 };
 
 } // namespace comm
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
index a671a04aa..cb1aaac39 100644
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
@@ -1,3312 +1,3383 @@
 #include "SQLiteQueryExecutor.h"
 #include "Logger.h"
 
 #include "../NativeModules/PersistentStorageUtilities/MessageOperationsUtilities/MessageTypeEnum.h"
 #include "../NativeModules/PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h"
 #include "entities/CommunityInfo.h"
 #include "entities/EntityQueryHelpers.h"
 #include "entities/EntryInfo.h"
 #include "entities/IntegrityThreadHash.h"
 #include "entities/KeyserverInfo.h"
 #include "entities/LocalMessageInfo.h"
 #include "entities/Metadata.h"
 #include "entities/SQLiteDataConverters.h"
 #include "entities/SyncedMetadataEntry.h"
 #include "entities/UserInfo.h"
 #include <fstream>
 #include <iostream>
 #include <thread>
 
 #ifndef EMSCRIPTEN
 #include "../CryptoTools/CryptoModule.h"
 #include "CommSecureStore.h"
 #include "PlatformSpecificTools.h"
 #include "StaffUtils.h"
 #endif
 
 const int CONTENT_ACCOUNT_ID = 1;
 const int NOTIFS_ACCOUNT_ID = 2;
 
 namespace comm {
 
 std::string SQLiteQueryExecutor::sqliteFilePath;
 std::once_flag SQLiteQueryExecutor::initialized;
 
 std::string SQLiteQueryExecutor::backupDataKey;
 int SQLiteQueryExecutor::backupDataKeySize = 64;
 
 std::string SQLiteQueryExecutor::backupLogDataKey;
 int SQLiteQueryExecutor::backupLogDataKeySize = 32;
 
 #ifndef EMSCRIPTEN
 NativeSQLiteConnectionManager SQLiteQueryExecutor::connectionManager;
 std::unordered_set<std::string> SQLiteQueryExecutor::backedUpTablesBlocklist = {
     "olm_persist_account",
     "olm_persist_sessions",
     "metadata",
     "outbound_p2p_messages",
     "inbound_p2p_messages",
     "integrity_store",
     "persist_storage",
     "keyservers",
 };
 #else
 SQLiteConnectionManager SQLiteQueryExecutor::connectionManager;
 #endif
 
 bool create_table(sqlite3 *db, std::string query, std::string tableName) {
   char *error;
   sqlite3_exec(db, query.c_str(), nullptr, nullptr, &error);
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error creating '" << tableName << "' table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_drafts_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS drafts (threadID TEXT UNIQUE PRIMARY KEY, "
       "text TEXT);";
   return create_table(db, query, "drafts");
 }
 
 bool rename_threadID_to_key(sqlite3 *db) {
   sqlite3_stmt *key_column_stmt;
   sqlite3_prepare_v2(
       db,
       "SELECT name AS col_name FROM pragma_table_xinfo ('drafts') WHERE "
       "col_name='key';",
       -1,
       &key_column_stmt,
       nullptr);
   sqlite3_step(key_column_stmt);
 
   auto num_bytes = sqlite3_column_bytes(key_column_stmt, 0);
   sqlite3_finalize(key_column_stmt);
   if (num_bytes) {
     return true;
   }
 
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE drafts RENAME COLUMN `threadID` TO `key`;",
       nullptr,
       nullptr,
       &error);
   if (error) {
     std::ostringstream stringStream;
     stringStream << "Error occurred renaming threadID column in drafts table "
                  << "to key: " << error;
     Logger::log(stringStream.str());
     sqlite3_free(error);
     return false;
   }
   return true;
 }
 
 bool create_persist_account_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS olm_persist_account("
       "id INTEGER UNIQUE PRIMARY KEY NOT NULL, "
       "account_data TEXT NOT NULL);";
   return create_table(db, query, "olm_persist_account");
 }
 
 bool create_persist_sessions_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS olm_persist_sessions("
       "target_user_id TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "session_data TEXT NOT NULL);";
   return create_table(db, query, "olm_persist_sessions");
 }
 
 bool drop_messages_table(sqlite3 *db) {
   char *error;
   sqlite3_exec(db, "DROP TABLE IF EXISTS messages;", nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error dropping 'messages' table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool recreate_messages_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS messages ( "
       "id TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "local_id TEXT, "
       "thread TEXT NOT NULL, "
       "user TEXT NOT NULL, "
       "type INTEGER NOT NULL, "
       "future_type INTEGER, "
       "content TEXT, "
       "time INTEGER NOT NULL);";
   return create_table(db, query, "messages");
 }
 
 bool create_messages_idx_thread_time(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "CREATE INDEX IF NOT EXISTS messages_idx_thread_time "
       "ON messages (thread, time);",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error creating (thread, time) index on messages table: "
                << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_messages_idx_target_message_type_time(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE messages "
       "  ADD COLUMN target_message TEXT "
       "  AS (IIF( "
       "    JSON_VALID(content), "
       "    JSON_EXTRACT(content, '$.targetMessageID'), "
       "    NULL "
       "  )); "
       "CREATE INDEX IF NOT EXISTS messages_idx_target_message_type_time "
       "  ON messages (target_message, type, time);",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream
       << "Error creating (target_message, type, time) index on messages table: "
       << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool update_messages_idx_target_message_type_time(sqlite3 *db) {
   char *error;
   int sidebarSourceTypeInt = static_cast<int>(MessageType::SIDEBAR_SOURCE);
   std::string sidebarSourceType = std::to_string(sidebarSourceTypeInt);
 
   auto query =
       "DROP INDEX IF EXISTS messages_idx_target_message_type_time;"
       "ALTER TABLE messages DROP COLUMN target_message;"
       "ALTER TABLE messages "
       "  ADD COLUMN target_message TEXT "
       "  AS (IIF("
       "    JSON_VALID(content),"
       "    COALESCE("
       "      JSON_EXTRACT(content, '$.targetMessageID'),"
       "      IIF("
       "        type = " +
       sidebarSourceType +
       "        , JSON_EXTRACT(content, '$.id'),"
       "        NULL"
       "      )"
       "    ),"
       "    NULL"
       "  ));"
       "CREATE INDEX IF NOT EXISTS messages_idx_target_message_type_time "
       "  ON messages (target_message, type, time);";
 
   sqlite3_exec(db, query.c_str(), nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream
       << "Error creating (target_message, type, time) index on messages table: "
       << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_media_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS media ( "
       "id TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "container TEXT NOT NULL, "
       "thread TEXT NOT NULL, "
       "uri TEXT NOT NULL, "
       "type TEXT NOT NULL, "
       "extras TEXT NOT NULL);";
   return create_table(db, query, "media");
 }
 
 bool create_media_idx_container(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "CREATE INDEX IF NOT EXISTS media_idx_container "
       "ON media (container);",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error creating (container) index on media table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_threads_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS threads ( "
       "id TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "type INTEGER NOT NULL, "
       "name TEXT, "
       "description TEXT, "
       "color TEXT NOT NULL, "
       "creation_time BIGINT NOT NULL, "
       "parent_thread_id TEXT, "
       "containing_thread_id TEXT, "
       "community TEXT, "
       "members TEXT NOT NULL, "
       "roles TEXT NOT NULL, "
       "current_user TEXT NOT NULL, "
       "source_message_id TEXT, "
       "replies_count INTEGER NOT NULL);";
   return create_table(db, query, "threads");
 }
 
 bool update_threadID_for_pending_threads_in_drafts(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "UPDATE drafts SET key = "
       "REPLACE(REPLACE(REPLACE(REPLACE(key, 'type4/', ''),"
       "'type5/', ''),'type6/', ''),'type7/', '')"
       "WHERE key LIKE 'pending/%'",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error update pending threadIDs on drafts table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool enable_write_ahead_logging_mode(sqlite3 *db) {
   char *error;
   sqlite3_exec(db, "PRAGMA journal_mode=wal;", nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error enabling write-ahead logging mode: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_metadata_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS metadata ( "
       "name TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "data TEXT);";
   return create_table(db, query, "metadata");
 }
 
 bool add_not_null_constraint_to_drafts(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "CREATE TABLE IF NOT EXISTS temporary_drafts ("
       "key TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "text TEXT NOT NULL);"
       "INSERT INTO temporary_drafts SELECT * FROM drafts "
       "WHERE key IS NOT NULL AND text IS NOT NULL;"
       "DROP TABLE drafts;"
       "ALTER TABLE temporary_drafts RENAME TO drafts;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error adding NOT NULL constraint to drafts table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool add_not_null_constraint_to_metadata(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "CREATE TABLE IF NOT EXISTS temporary_metadata ("
       "name TEXT UNIQUE PRIMARY KEY NOT NULL, "
       "data TEXT NOT NULL);"
       "INSERT INTO temporary_metadata SELECT * FROM metadata "
       "WHERE data IS NOT NULL;"
       "DROP TABLE metadata;"
       "ALTER TABLE temporary_metadata RENAME TO metadata;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error adding NOT NULL constraint to metadata table: "
                << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool add_avatar_column_to_threads_table(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE threads ADD COLUMN avatar TEXT;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error adding avatar column to threads table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool add_pinned_count_column_to_threads(sqlite3 *db) {
   sqlite3_stmt *pinned_column_stmt;
   sqlite3_prepare_v2(
       db,
       "SELECT name AS col_name FROM pragma_table_xinfo ('threads') WHERE "
       "col_name='pinned_count';",
       -1,
       &pinned_column_stmt,
       nullptr);
   sqlite3_step(pinned_column_stmt);
 
   auto num_bytes = sqlite3_column_bytes(pinned_column_stmt, 0);
   sqlite3_finalize(pinned_column_stmt);
 
   if (num_bytes) {
     return true;
   }
 
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE threads ADD COLUMN pinned_count INTEGER NOT NULL DEFAULT 0;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error adding pinned_count column to threads table: "
                << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_message_store_threads_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS message_store_threads ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  start_reached INTEGER NOT NULL,"
       "  last_navigated_to BIGINT NOT NULL,"
       "  last_pruned BIGINT NOT NULL"
       ");";
   return create_table(db, query, "message_store_threads");
 }
 
 bool create_reports_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS reports ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  report TEXT NOT NULL"
       ");";
   return create_table(db, query, "reports");
 }
 
 bool create_persist_storage_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS persist_storage ("
       "  key TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  item TEXT NOT NULL"
       ");";
   return create_table(db, query, "persist_storage");
 }
 
 bool recreate_message_store_threads_table(sqlite3 *db) {
   char *errMsg = 0;
 
   // 1. Create table without `last_navigated_to` or `last_pruned`.
   std::string create_new_table_query =
       "CREATE TABLE IF NOT EXISTS temp_message_store_threads ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  start_reached INTEGER NOT NULL"
       ");";
 
   if (sqlite3_exec(db, create_new_table_query.c_str(), NULL, NULL, &errMsg) !=
       SQLITE_OK) {
     Logger::log(
         "Error creating temp_message_store_threads: " + std::string{errMsg});
     sqlite3_free(errMsg);
     return false;
   }
 
   // 2. Dump data from existing `message_store_threads` table into temp table.
   std::string copy_data_query =
       "INSERT INTO temp_message_store_threads (id, start_reached)"
       "SELECT id, start_reached FROM message_store_threads;";
 
   if (sqlite3_exec(db, copy_data_query.c_str(), NULL, NULL, &errMsg) !=
       SQLITE_OK) {
     Logger::log(
         "Error dumping data from existing message_store_threads to "
         "temp_message_store_threads: " +
         std::string{errMsg});
     sqlite3_free(errMsg);
     return false;
   }
 
   // 3. Drop the existing `message_store_threads` table.
   std::string drop_old_table_query = "DROP TABLE message_store_threads;";
 
   if (sqlite3_exec(db, drop_old_table_query.c_str(), NULL, NULL, &errMsg) !=
       SQLITE_OK) {
     Logger::log(
         "Error dropping message_store_threads table: " + std::string{errMsg});
     sqlite3_free(errMsg);
     return false;
   }
 
   // 4. Rename the temp table back to `message_store_threads`.
   std::string rename_table_query =
       "ALTER TABLE temp_message_store_threads RENAME TO message_store_threads;";
 
   if (sqlite3_exec(db, rename_table_query.c_str(), NULL, NULL, &errMsg) !=
       SQLITE_OK) {
     Logger::log(
         "Error renaming temp_message_store_threads to message_store_threads: " +
         std::string{errMsg});
     sqlite3_free(errMsg);
     return false;
   }
 
   return true;
 }
 
 bool create_users_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS users ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  user_info TEXT NOT NULL"
       ");";
   return create_table(db, query, "users");
 }
 
 bool create_keyservers_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS keyservers ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  keyserver_info TEXT NOT NULL"
       ");";
   return create_table(db, query, "keyservers");
 }
 
 bool enable_rollback_journal_mode(sqlite3 *db) {
   char *error;
   sqlite3_exec(db, "PRAGMA journal_mode=DELETE;", nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::stringstream error_message;
   error_message << "Error disabling write-ahead logging mode: " << error;
   Logger::log(error_message.str());
   sqlite3_free(error);
   return false;
 }
 
 bool create_communities_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS communities ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  community_info TEXT NOT NULL"
       ");";
   return create_table(db, query, "communities");
 }
 
 bool create_messages_to_device_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS messages_to_device ("
       "  message_id TEXT NOT NULL,"
       "  device_id TEXT NOT NULL,"
       "  user_id TEXT NOT NULL,"
       "  timestamp BIGINT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  ciphertext TEXT NOT NULL,"
       "  PRIMARY KEY (message_id, device_id)"
       ");"
 
       "CREATE INDEX IF NOT EXISTS messages_to_device_idx_id_timestamp"
       "  ON messages_to_device (device_id, timestamp);";
 
   return create_table(db, query, "messages_to_device");
 }
 
 bool create_integrity_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS integrity_store ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  thread_hash TEXT NOT NULL"
       ");";
   return create_table(db, query, "integrity_store");
 }
 
 bool create_synced_metadata_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS synced_metadata ("
       "  name TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  data TEXT NOT NULL"
       ");";
   return create_table(db, query, "synced_metadata");
 }
 
 bool create_keyservers_synced(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS keyservers_synced ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  keyserver_info TEXT NOT NULL"
       ");";
   bool success = create_table(db, query, "keyservers_synced");
   if (!success) {
     return false;
   }
 
   std::string copyData =
       "INSERT INTO keyservers_synced (id, keyserver_info)"
       "SELECT id, keyserver_info "
       "FROM keyservers;";
 
   char *error;
   sqlite3_exec(db, copyData.c_str(), nullptr, nullptr, &error);
   if (error) {
     return false;
   }
 
   return true;
 }
 
 bool create_aux_user_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS aux_users ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  aux_user_info TEXT NOT NULL"
       ");";
   return create_table(db, query, "aux_users");
 }
 
 bool add_version_column_to_olm_persist_sessions_table(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE olm_persist_sessions "
       "  RENAME COLUMN `target_user_id` TO `target_device_id`; "
       "ALTER TABLE olm_persist_sessions "
       "  ADD COLUMN version INTEGER NOT NULL DEFAULT 1;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error updating olm_persist_sessions table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_thread_activity_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS thread_activity ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  thread_activity_store_entry TEXT NOT NULL"
       ");";
   return create_table(db, query, "thread_activity");
 }
 
 bool create_received_messages_to_device(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS received_messages_to_device ("
       "  id INTEGER PRIMARY KEY,"
       "  message_id TEXT NOT NULL,"
       "  sender_device_id TEXT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  status TEXT NOT NULL"
       ");";
   return create_table(db, query, "received_messages_to_device");
 }
 
 bool recreate_outbound_p2p_messages_table(sqlite3 *db) {
   std::string query =
       "DROP TABLE IF EXISTS messages_to_device;"
       "CREATE TABLE IF NOT EXISTS outbound_p2p_messages ("
       "  message_id TEXT NOT NULL,"
       "  device_id TEXT NOT NULL,"
       "  user_id TEXT NOT NULL,"
       "  timestamp BIGINT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  ciphertext TEXT NOT NULL,"
       "  status TEXT NOT NULL,"
       "  PRIMARY KEY (message_id, device_id)"
       ");"
 
       "CREATE INDEX IF NOT EXISTS outbound_p2p_messages_idx_id_timestamp"
       "  ON outbound_p2p_messages (device_id, timestamp);";
 
   return create_table(db, query, "outbound_p2p_messages");
 }
 
 bool create_entries_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS entries ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  entry TEXT NOT NULL"
       ");";
   return create_table(db, query, "entries");
 }
 
 bool create_message_store_local_table(sqlite3 *db) {
   std::string query =
       "CREATE TABLE IF NOT EXISTS message_store_local ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  local_message_info TEXT NOT NULL"
       ");";
   return create_table(db, query, "message_store_local");
 }
 
 bool add_supports_auto_retry_column_to_p2p_messages_table(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE outbound_p2p_messages"
       "  ADD COLUMN supports_auto_retry INTEGER DEFAULT 0",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error updating outbound_p2p_messages table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 bool create_message_search_table(sqlite3 *db) {
   std::string query =
       "CREATE VIRTUAL TABLE IF NOT EXISTS message_search USING fts5("
       "  original_message_id UNINDEXED,"
       "  message_id UNINDEXED,"
       "  processed_content,"
       "  tokenize = porter"
       ");";
   return create_table(db, query, "message_search");
 }
 
 bool recreate_inbound_p2p_messages_table(sqlite3 *db) {
   std::string query =
       "DROP TABLE IF EXISTS received_messages_to_device;"
       "CREATE TABLE IF NOT EXISTS inbound_p2p_messages ("
       "  id INTEGER PRIMARY KEY,"
       "  message_id TEXT NOT NULL,"
       "  sender_device_id TEXT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  status TEXT NOT NULL,"
       "  sender_user_id TEXT NOT NULL"
       ");";
 
   return create_table(db, query, "inbound_p2p_messages");
 }
 
 bool add_timestamps_column_to_threads_table(sqlite3 *db) {
   char *error;
   sqlite3_exec(
       db,
       "ALTER TABLE threads"
       "  ADD COLUMN timestamps TEXT;",
       nullptr,
       nullptr,
       &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error updating threads table: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
+bool create_dm_operations_table(sqlite3 *db) {
+  std::string query =
+      "CREATE TABLE IF NOT EXISTS dm_operations ("
+      "  id TEXT PRIMARY KEY,"
+      "  type TEXT NOT NULL,"
+      "  operation TEXT NOT NULL"
+      ");"
+      "CREATE INDEX IF NOT EXISTS dm_operations_idx_type"
+      "  ON dm_operations (type);";
+
+  return create_table(db, query, "dm_operations");
+}
+
 bool create_schema(sqlite3 *db) {
   char *error;
   int sidebarSourceTypeInt = static_cast<int>(MessageType::SIDEBAR_SOURCE);
   std::string sidebarSourceType = std::to_string(sidebarSourceTypeInt);
   auto query =
       "CREATE TABLE IF NOT EXISTS drafts ("
       "  key TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  text TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS messages ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  local_id TEXT,"
       "  thread TEXT NOT NULL,"
       "  user TEXT NOT NULL,"
       "  type INTEGER NOT NULL,"
       "  future_type INTEGER,"
       "  content TEXT,"
       "  time INTEGER NOT NULL,"
       "  target_message TEXT AS ("
       "    IIF("
       "      JSON_VALID(content),"
       "      COALESCE("
       "        JSON_EXTRACT(content, '$.targetMessageID'),"
       "        IIF("
       "          type = " +
       sidebarSourceType +
       "          , JSON_EXTRACT(content, '$.id'),"
       "          NULL"
       "        )"
       "      ),"
       "      NULL"
       "    )"
       "  )"
       ");"
 
       "CREATE TABLE IF NOT EXISTS olm_persist_account ("
       "  id INTEGER UNIQUE PRIMARY KEY NOT NULL,"
       "  account_data TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS olm_persist_sessions ("
       "  target_device_id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  session_data TEXT NOT NULL,"
       "  version INTEGER NOT NULL DEFAULT 1"
       ");"
 
       "CREATE TABLE IF NOT EXISTS media ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  container TEXT NOT NULL,"
       "  thread TEXT NOT NULL,"
       "  uri TEXT NOT NULL,"
       "  type TEXT NOT NULL,"
       "  extras TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS threads ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  type INTEGER NOT NULL,"
       "  name TEXT,"
       "  description TEXT,"
       "  color TEXT NOT NULL,"
       "  creation_time BIGINT NOT NULL,"
       "  parent_thread_id TEXT,"
       "  containing_thread_id TEXT,"
       "  community TEXT,"
       "  members TEXT NOT NULL,"
       "  roles TEXT NOT NULL,"
       "  current_user TEXT NOT NULL,"
       "  source_message_id TEXT,"
       "  replies_count INTEGER NOT NULL,"
       "  avatar TEXT,"
       "  pinned_count INTEGER NOT NULL DEFAULT 0,"
       "  timestamps TEXT"
       ");"
 
       "CREATE TABLE IF NOT EXISTS metadata ("
       "  name TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  data TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS message_store_threads ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  start_reached INTEGER NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS reports ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  report TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS persist_storage ("
       "  key TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  item TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS users ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  user_info TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS keyservers ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  keyserver_info TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS keyservers_synced ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  keyserver_info TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS communities ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  community_info TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS outbound_p2p_messages ("
       "  message_id TEXT NOT NULL,"
       "  device_id TEXT NOT NULL,"
       "  user_id TEXT NOT NULL,"
       "  timestamp BIGINT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  ciphertext TEXT NOT NULL,"
       "  status TEXT NOT NULL,"
       "  supports_auto_retry INTEGER DEFAULT 0,"
       "  PRIMARY KEY (message_id, device_id)"
       ");"
 
       "CREATE TABLE IF NOT EXISTS integrity_store ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  thread_hash TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS synced_metadata ("
       "  name TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  data TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS aux_users ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  aux_user_info TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS thread_activity ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  thread_activity_store_entry TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS inbound_p2p_messages ("
       "  id INTEGER PRIMARY KEY,"
       "  message_id TEXT NOT NULL,"
       "  sender_device_id TEXT NOT NULL,"
       "  plaintext TEXT NOT NULL,"
       "  status TEXT NOT NULL,"
       "  sender_user_id TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS entries ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  entry TEXT NOT NULL"
       ");"
 
       "CREATE TABLE IF NOT EXISTS message_store_local ("
       "  id TEXT UNIQUE PRIMARY KEY NOT NULL,"
       "  local_message_info TEXT NOT NULL"
       ");"
 
       "CREATE VIRTUAL TABLE IF NOT EXISTS message_search USING fts5("
       "  original_message_id UNINDEXED,"
       "  message_id UNINDEXED,"
       "  processed_content,"
       "  tokenize = porter"
       ");"
 
+      "CREATE TABLE IF NOT EXISTS dm_operations ("
+      "  id TEXT PRIMARY KEY,"
+      "  type TEXT NOT NULL,"
+      "  operation TEXT NOT NULL"
+      ");"
+
       "CREATE INDEX IF NOT EXISTS media_idx_container"
       "  ON media (container);"
 
       "CREATE INDEX IF NOT EXISTS messages_idx_thread_time"
       "  ON messages (thread, time);"
 
       "CREATE INDEX IF NOT EXISTS messages_idx_target_message_type_time"
       "  ON messages (target_message, type, time);"
 
       "CREATE INDEX IF NOT EXISTS outbound_p2p_messages_idx_id_timestamp"
-      "  ON outbound_p2p_messages (device_id, timestamp);";
+      "  ON outbound_p2p_messages (device_id, timestamp);"
+
+      "CREATE INDEX IF NOT EXISTS dm_operations_idx_type"
+      "  ON dm_operations (type);";
 
   sqlite3_exec(db, query.c_str(), nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream stringStream;
   stringStream << "Error creating tables: " << error;
   Logger::log(stringStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 void set_encryption_key(
     sqlite3 *db,
     const std::string &encryptionKey = SQLiteQueryExecutor::backupDataKey) {
   std::string set_encryption_key_query =
       "PRAGMA key = \"x'" + encryptionKey + "'\";";
 
   char *error_set_key;
   sqlite3_exec(
       db, set_encryption_key_query.c_str(), nullptr, nullptr, &error_set_key);
 
   if (error_set_key) {
     std::ostringstream error_message;
     error_message << "Failed to set encryption key: " << error_set_key;
     throw std::system_error(
         ECANCELED, std::generic_category(), error_message.str());
   }
 }
 
 int get_database_version(sqlite3 *db) {
   sqlite3_stmt *user_version_stmt;
   sqlite3_prepare_v2(
       db, "PRAGMA user_version;", -1, &user_version_stmt, nullptr);
   sqlite3_step(user_version_stmt);
 
   int current_user_version = sqlite3_column_int(user_version_stmt, 0);
   sqlite3_finalize(user_version_stmt);
   return current_user_version;
 }
 
 bool set_database_version(sqlite3 *db, int db_version) {
   std::stringstream update_version;
   update_version << "PRAGMA user_version=" << db_version << ";";
   auto update_version_str = update_version.str();
 
   char *error;
   sqlite3_exec(db, update_version_str.c_str(), nullptr, nullptr, &error);
 
   if (!error) {
     return true;
   }
 
   std::ostringstream errorStream;
   errorStream << "Error setting database version to " << db_version << ": "
               << error;
   Logger::log(errorStream.str());
 
   sqlite3_free(error);
   return false;
 }
 
 // We don't want to run `PRAGMA key = ...;`
 // on main web database. The context is here:
 // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web
 void default_on_db_open_callback(sqlite3 *db) {
 #ifndef EMSCRIPTEN
   set_encryption_key(db);
 #endif
 }
 
 // This is a temporary solution. In future we want to keep
 // a separate table for blob hashes. Tracked on Linear:
 // https://linear.app/comm/issue/ENG-6261/introduce-blob-hash-table
 std::string blob_hash_from_blob_service_uri(const std::string &media_uri) {
   static const std::string blob_service_prefix = "comm-blob-service://";
   return media_uri.substr(blob_service_prefix.size());
 }
 
 bool file_exists(const std::string &file_path) {
   std::ifstream file(file_path.c_str());
   return file.good();
 }
 
 void attempt_delete_file(
     const std::string &file_path,
     const char *error_message) {
   if (std::remove(file_path.c_str())) {
     throw std::system_error(errno, std::generic_category(), error_message);
   }
 }
 
 void attempt_rename_file(
     const std::string &old_path,
     const std::string &new_path,
     const char *error_message) {
   if (std::rename(old_path.c_str(), new_path.c_str())) {
     throw std::system_error(errno, std::generic_category(), error_message);
   }
 }
 
 bool is_database_queryable(
     sqlite3 *db,
     bool use_encryption_key,
     const std::string &path = SQLiteQueryExecutor::sqliteFilePath,
     const std::string &encryptionKey = SQLiteQueryExecutor::backupDataKey) {
   char *err_msg;
   sqlite3_open(path.c_str(), &db);
   // According to SQLCipher documentation running some SELECT is the only way to
   // check for key validity
   if (use_encryption_key) {
     set_encryption_key(db, encryptionKey);
   }
   sqlite3_exec(
       db, "SELECT COUNT(*) FROM sqlite_master;", nullptr, nullptr, &err_msg);
   sqlite3_close(db);
   return !err_msg;
 }
 
 void validate_encryption() {
   std::string temp_encrypted_db_path =
       SQLiteQueryExecutor::sqliteFilePath + "_temp_encrypted";
 
   bool temp_encrypted_exists = file_exists(temp_encrypted_db_path);
   bool default_location_exists =
       file_exists(SQLiteQueryExecutor::sqliteFilePath);
 
   if (temp_encrypted_exists && default_location_exists) {
     Logger::log(
         "Previous encryption attempt failed. Repeating encryption process from "
         "the beginning.");
     attempt_delete_file(
         temp_encrypted_db_path,
         "Failed to delete corrupted encrypted database.");
   } else if (temp_encrypted_exists && !default_location_exists) {
     Logger::log(
         "Moving temporary encrypted database to default location failed in "
         "previous encryption attempt. Repeating rename step.");
     attempt_rename_file(
         temp_encrypted_db_path,
         SQLiteQueryExecutor::sqliteFilePath,
         "Failed to move encrypted database to default location.");
     return;
   } else if (!default_location_exists) {
     Logger::log(
         "Database not present yet. It will be created encrypted under default "
         "path.");
     return;
   }
 
   sqlite3 *db;
   if (is_database_queryable(db, true)) {
     Logger::log(
         "Database exists under default path and it is correctly encrypted.");
     return;
   }
 
   if (!is_database_queryable(db, false)) {
     Logger::log(
         "Database exists but it is encrypted with key that was lost. "
         "Attempting database deletion. New encrypted one will be created.");
     attempt_delete_file(
         SQLiteQueryExecutor::sqliteFilePath.c_str(),
         "Failed to delete database encrypted with lost key.");
     return;
   } else {
     Logger::log(
         "Database exists but it is not encrypted. Attempting encryption "
         "process.");
   }
   sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db);
 
   std::string createEncryptedCopySQL = "ATTACH DATABASE '" +
       temp_encrypted_db_path +
       "' AS encrypted_comm "
       "KEY \"x'" +
       SQLiteQueryExecutor::backupDataKey +
       "'\";"
       "SELECT sqlcipher_export('encrypted_comm');"
       "DETACH DATABASE encrypted_comm;";
 
   char *encryption_error;
   sqlite3_exec(
       db, createEncryptedCopySQL.c_str(), nullptr, nullptr, &encryption_error);
 
   if (encryption_error) {
     throw std::system_error(
         ECANCELED,
         std::generic_category(),
         "Failed to create encrypted copy of the original database.");
   }
   sqlite3_close(db);
 
   attempt_delete_file(
       SQLiteQueryExecutor::sqliteFilePath,
       "Failed to delete unencrypted database.");
   attempt_rename_file(
       temp_encrypted_db_path,
       SQLiteQueryExecutor::sqliteFilePath,
       "Failed to move encrypted database to default location.");
   Logger::log("Encryption completed successfully.");
 }
 
 typedef bool ShouldBeInTransaction;
 typedef std::function<bool(sqlite3 *)> MigrateFunction;
 typedef std::pair<MigrateFunction, ShouldBeInTransaction> SQLiteMigration;
 std::vector<std::pair<unsigned int, SQLiteMigration>> migrations{
     {{1, {create_drafts_table, true}},
      {2, {rename_threadID_to_key, true}},
      {4, {create_persist_account_table, true}},
      {5, {create_persist_sessions_table, true}},
      {15, {create_media_table, true}},
      {16, {drop_messages_table, true}},
      {17, {recreate_messages_table, true}},
      {18, {create_messages_idx_thread_time, true}},
      {19, {create_media_idx_container, true}},
      {20, {create_threads_table, true}},
      {21, {update_threadID_for_pending_threads_in_drafts, true}},
      {22, {enable_write_ahead_logging_mode, false}},
      {23, {create_metadata_table, true}},
      {24, {add_not_null_constraint_to_drafts, true}},
      {25, {add_not_null_constraint_to_metadata, true}},
      {26, {add_avatar_column_to_threads_table, true}},
      {27, {add_pinned_count_column_to_threads, true}},
      {28, {create_message_store_threads_table, true}},
      {29, {create_reports_table, true}},
      {30, {create_persist_storage_table, true}},
      {31, {recreate_message_store_threads_table, true}},
      {32, {create_users_table, true}},
      {33, {create_keyservers_table, true}},
      {34, {enable_rollback_journal_mode, false}},
      {35, {create_communities_table, true}},
      {36, {create_messages_to_device_table, true}},
      {37, {create_integrity_table, true}},
      {38, {[](sqlite3 *) { return true; }, false}},
      {39, {create_synced_metadata_table, true}},
      {40, {create_keyservers_synced, true}},
      {41, {create_aux_user_table, true}},
      {42, {add_version_column_to_olm_persist_sessions_table, true}},
      {43, {create_thread_activity_table, true}},
      {44, {create_received_messages_to_device, true}},
      {45, {recreate_outbound_p2p_messages_table, true}},
      {46, {create_entries_table, true}},
      {47, {create_message_store_local_table, true}},
      {48, {create_messages_idx_target_message_type_time, true}},
      {49, {add_supports_auto_retry_column_to_p2p_messages_table, true}},
      {50, {create_message_search_table, true}},
      {51, {update_messages_idx_target_message_type_time, true}},
      {52, {recreate_inbound_p2p_messages_table, true}},
-     {53, {add_timestamps_column_to_threads_table, true}}}};
+     {53, {add_timestamps_column_to_threads_table, true}},
+     {54, {create_dm_operations_table, true}}}};
 
 enum class MigrationResult { SUCCESS, FAILURE, NOT_APPLIED };
 
 MigrationResult applyMigrationWithTransaction(
     sqlite3 *db,
     const MigrateFunction &migrate,
     int index) {
   sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
   auto db_version = get_database_version(db);
   if (index <= db_version) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return MigrationResult::NOT_APPLIED;
   }
   auto rc = migrate(db);
   if (!rc) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return MigrationResult::FAILURE;
   }
   auto database_version_set = set_database_version(db, index);
   if (!database_version_set) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return MigrationResult::FAILURE;
   }
   sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr);
   return MigrationResult::SUCCESS;
 }
 
 MigrationResult applyMigrationWithoutTransaction(
     sqlite3 *db,
     const MigrateFunction &migrate,
     int index) {
   auto db_version = get_database_version(db);
   if (index <= db_version) {
     return MigrationResult::NOT_APPLIED;
   }
   auto rc = migrate(db);
   if (!rc) {
     return MigrationResult::FAILURE;
   }
   sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
   auto inner_db_version = get_database_version(db);
   if (index <= inner_db_version) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return MigrationResult::NOT_APPLIED;
   }
   auto database_version_set = set_database_version(db, index);
   if (!database_version_set) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return MigrationResult::FAILURE;
   }
   sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr);
   return MigrationResult::SUCCESS;
 }
 
 bool set_up_database(sqlite3 *db) {
   sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
   auto db_version = get_database_version(db);
   auto latest_version = migrations.back().first;
   if (db_version == latest_version) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return true;
   }
   if (db_version != 0 || !create_schema(db) ||
       !set_database_version(db, latest_version)) {
     sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
     return false;
   }
   sqlite3_exec(db, "END TRANSACTION;", nullptr, nullptr, nullptr);
   return true;
 }
 
 void SQLiteQueryExecutor::migrate() {
 // We don't want to run `PRAGMA key = ...;`
 // on main web database. The context is here:
 // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web
 #ifndef EMSCRIPTEN
   validate_encryption();
 #endif
 
   sqlite3 *db;
   sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db);
   default_on_db_open_callback(db);
 
   std::stringstream db_path;
   db_path << "db path: " << SQLiteQueryExecutor::sqliteFilePath.c_str()
           << std::endl;
   Logger::log(db_path.str());
 
   auto db_version = get_database_version(db);
   std::stringstream version_msg;
   version_msg << "db version: " << db_version << std::endl;
   Logger::log(version_msg.str());
 
   if (db_version == 0) {
     auto db_created = set_up_database(db);
     if (!db_created) {
       sqlite3_close(db);
       Logger::log("Database structure creation error.");
       throw std::runtime_error("Database structure creation error");
     }
     Logger::log("Database structure created.");
 
     sqlite3_close(db);
     return;
   }
 
   for (const auto &[idx, migration] : migrations) {
     const auto &[applyMigration, shouldBeInTransaction] = migration;
 
     MigrationResult migrationResult;
     if (shouldBeInTransaction) {
       migrationResult = applyMigrationWithTransaction(db, applyMigration, idx);
     } else {
       migrationResult =
           applyMigrationWithoutTransaction(db, applyMigration, idx);
     }
 
     if (migrationResult == MigrationResult::NOT_APPLIED) {
       continue;
     }
 
     std::stringstream migration_msg;
     if (migrationResult == MigrationResult::FAILURE) {
       migration_msg << "migration " << idx << " failed." << std::endl;
       Logger::log(migration_msg.str());
       sqlite3_close(db);
       throw std::runtime_error(migration_msg.str());
     }
     if (migrationResult == MigrationResult::SUCCESS) {
       migration_msg << "migration " << idx << " succeeded." << std::endl;
       Logger::log(migration_msg.str());
     }
   }
 
   sqlite3_close(db);
 }
 
 SQLiteQueryExecutor::SQLiteQueryExecutor() {
   SQLiteQueryExecutor::migrate();
 #ifndef EMSCRIPTEN
   SQLiteQueryExecutor::initializeTablesForLogMonitoring();
 
   std::string currentBackupID = this->getMetadata("backupID");
   if (!StaffUtils::isStaffRelease() || !currentBackupID.size()) {
     return;
   }
   SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true);
 #endif
 }
 
 SQLiteQueryExecutor::SQLiteQueryExecutor(std::string sqliteFilePath) {
   SQLiteQueryExecutor::sqliteFilePath = sqliteFilePath;
   SQLiteQueryExecutor::migrate();
 }
 
 sqlite3 *SQLiteQueryExecutor::getConnection() {
   if (SQLiteQueryExecutor::connectionManager.getConnection()) {
     return SQLiteQueryExecutor::connectionManager.getConnection();
   }
   SQLiteQueryExecutor::connectionManager.initializeConnection(
       SQLiteQueryExecutor::sqliteFilePath, default_on_db_open_callback);
   return SQLiteQueryExecutor::connectionManager.getConnection();
 }
 
 void SQLiteQueryExecutor::closeConnection() {
   SQLiteQueryExecutor::connectionManager.closeConnection();
 }
 
 SQLiteQueryExecutor::~SQLiteQueryExecutor() {
   SQLiteQueryExecutor::closeConnection();
 }
 
 std::string SQLiteQueryExecutor::getDraft(std::string key) const {
   static std::string getDraftByPrimaryKeySQL =
       "SELECT * "
       "FROM drafts "
       "WHERE key = ?;";
   std::unique_ptr<Draft> draft = getEntityByPrimaryKey<Draft>(
       SQLiteQueryExecutor::getConnection(), getDraftByPrimaryKeySQL, key);
   return (draft == nullptr) ? "" : draft->text;
 }
 
 std::unique_ptr<Thread>
 SQLiteQueryExecutor::getThread(std::string threadID) const {
   static std::string getThreadByPrimaryKeySQL =
       "SELECT * "
       "FROM threads "
       "WHERE id = ?;";
   return getEntityByPrimaryKey<Thread>(
       SQLiteQueryExecutor::getConnection(), getThreadByPrimaryKeySQL, threadID);
 }
 
 void SQLiteQueryExecutor::updateDraft(std::string key, std::string text) const {
   static std::string replaceDraftSQL =
       "REPLACE INTO drafts (key, text) "
       "VALUES (?, ?);";
   Draft draft = {key, text};
   replaceEntity<Draft>(
       SQLiteQueryExecutor::getConnection(), replaceDraftSQL, draft);
 }
 
 bool SQLiteQueryExecutor::moveDraft(std::string oldKey, std::string newKey)
     const {
   std::string draftText = this->getDraft(oldKey);
   if (!draftText.size()) {
     return false;
   }
   static std::string rekeyDraftSQL =
       "UPDATE OR REPLACE drafts "
       "SET key = ? "
       "WHERE key = ?;";
   rekeyAllEntities(
       SQLiteQueryExecutor::getConnection(), rekeyDraftSQL, oldKey, newKey);
   return true;
 }
 
 std::vector<Draft> SQLiteQueryExecutor::getAllDrafts() const {
   static std::string getAllDraftsSQL =
       "SELECT * "
       "FROM drafts;";
   return getAllEntities<Draft>(
       SQLiteQueryExecutor::getConnection(), getAllDraftsSQL);
 }
 
 void SQLiteQueryExecutor::removeAllDrafts() const {
   static std::string removeAllDraftsSQL = "DELETE FROM drafts;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllDraftsSQL);
 }
 
 void SQLiteQueryExecutor::removeDrafts(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeDraftsByKeysSQLStream;
   removeDraftsByKeysSQLStream << "DELETE FROM drafts "
                                  "WHERE key IN "
                               << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeDraftsByKeysSQLStream.str(),
       ids);
 }
 
 void SQLiteQueryExecutor::removeAllMessages() const {
   static std::string removeAllMessagesSQL = "DELETE FROM messages;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllMessagesSQL);
 }
 
 std::string SQLiteQueryExecutor::getThickThreadTypesList() const {
   std::stringstream resultStream;
   for (auto it = THICK_THREAD_TYPES.begin(); it != THICK_THREAD_TYPES.end();
        ++it) {
     int typeInt = static_cast<int>(*it);
     resultStream << typeInt;
 
     if (it + 1 != THICK_THREAD_TYPES.end()) {
       resultStream << ",";
     }
   }
   return resultStream.str();
 }
 
 std::vector<MessageEntity> SQLiteQueryExecutor::getInitialMessages() const {
   static std::string getInitialMessagesSQL =
       "SELECT "
       "  s.id, s.local_id, s.thread, s.user, s.type, s.future_type, "
       "  s.content, s.time, m.id, m.container, m.thread, m.uri, m.type, "
       "  m.extras "
       "FROM ( "
       "  SELECT "
       "    m.*, "
       "    ROW_NUMBER() OVER ( "
       "      PARTITION BY thread ORDER BY m.time DESC, m.id DESC "
       "    ) AS r "
       "  FROM messages AS m "
       ") AS s "
       "LEFT JOIN media AS m "
       "  ON s.id = m.container "
       "INNER JOIN threads AS t "
       "  ON s.thread = t.id "
       "WHERE s.r <= 20 OR t.type NOT IN ( " +
       this->getThickThreadTypesList() +
       ") "
       "ORDER BY s.time, s.id;";
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       getInitialMessagesSQL,
       "Failed to retrieve initial messages.");
   return this->processMessagesResults(preparedSQL);
 }
 
 std::vector<MessageEntity> SQLiteQueryExecutor::fetchMessages(
     std::string threadID,
     int limit,
     int offset) const {
   static std::string query =
       "SELECT "
       "  m.id, m.local_id, m.thread, m.user, m.type, m.future_type, "
       "  m.content, m.time, media.id, media.container, media.thread, "
       "  media.uri, media.type, media.extras "
       "FROM messages AS m "
       "LEFT JOIN media "
       "  ON m.id = media.container "
       "WHERE m.thread = ? "
       "ORDER BY m.time DESC, m.id DESC "
       "LIMIT ? OFFSET ?;";
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(), query, "Failed to fetch messages.");
 
   bindStringToSQL(threadID.c_str(), preparedSQL, 1);
   bindIntToSQL(limit, preparedSQL, 2);
   bindIntToSQL(offset, preparedSQL, 3);
 
   return this->processMessagesResults(preparedSQL);
 }
 
 std::vector<MessageEntity> SQLiteQueryExecutor::processMessagesResults(
     SQLiteStatementWrapper &preparedSQL) const {
   std::string prevMsgIdx{};
   std::vector<MessageEntity> messages;
 
   for (int stepResult = sqlite3_step(preparedSQL); stepResult == SQLITE_ROW;
        stepResult = sqlite3_step(preparedSQL)) {
     Message message = Message::fromSQLResult(preparedSQL, 0);
     if (message.id == prevMsgIdx) {
       messages.back().second.push_back(Media::fromSQLResult(preparedSQL, 8));
     } else {
       prevMsgIdx = message.id;
       std::vector<Media> mediaForMsg;
       if (sqlite3_column_type(preparedSQL, 8) != SQLITE_NULL) {
         mediaForMsg.push_back(Media::fromSQLResult(preparedSQL, 8));
       }
       messages.push_back(std::make_pair(std::move(message), mediaForMsg));
     }
   }
   return messages;
 }
 
 void SQLiteQueryExecutor::removeMessages(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeMessagesByKeysSQLStream;
   removeMessagesByKeysSQLStream << "DELETE FROM messages "
                                    "WHERE id IN "
                                 << getSQLStatementArray(ids.size()) << ";";
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeMessagesByKeysSQLStream.str(),
       ids);
 }
 
 void SQLiteQueryExecutor::removeMessagesForThreads(
     const std::vector<std::string> &threadIDs) const {
   if (!threadIDs.size()) {
     return;
   }
 
   std::stringstream removeMessagesByKeysSQLStream;
   removeMessagesByKeysSQLStream << "DELETE FROM messages "
                                    "WHERE thread IN "
                                 << getSQLStatementArray(threadIDs.size())
                                 << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeMessagesByKeysSQLStream.str(),
       threadIDs);
 }
 
 void SQLiteQueryExecutor::replaceMessage(const Message &message) const {
   static std::string replaceMessageSQL =
       "REPLACE INTO messages "
       "(id, local_id, thread, user, type, future_type, content, time) "
       "VALUES (?, ?, ?, ?, ?, ?, ?, ?);";
 
   replaceEntity<Message>(
       SQLiteQueryExecutor::getConnection(), replaceMessageSQL, message);
 }
 
 void SQLiteQueryExecutor::updateMessageSearchIndex(
     std::string originalMessageID,
     std::string messageID,
     std::string processedContent) const {
 
   sqlite3 *db = SQLiteQueryExecutor::getConnection();
   int bindResult = 0;
   std::unique_ptr<SQLiteStatementWrapper> preparedSQL;
 
   static std::string insertMessageSearchResultSQL =
       "INSERT INTO message_search("
       "  original_message_id, message_id, processed_content) "
       "VALUES (?, ?, ?);";
   static std::string updateMessageSearchResultSQL =
       "UPDATE message_search "
       "SET message_id = ?, processed_content = ? "
       "WHERE original_message_id = ?;";
 
   if (originalMessageID == messageID) {
     preparedSQL = std::make_unique<SQLiteStatementWrapper>(
         db,
         insertMessageSearchResultSQL,
         "Failed to update message search entry.");
 
     bindStringToSQL(originalMessageID, *preparedSQL, 1);
     bindStringToSQL(messageID, *preparedSQL, 2);
     bindResult = bindStringToSQL(processedContent, *preparedSQL, 3);
   } else {
     preparedSQL = std::make_unique<SQLiteStatementWrapper>(
         db,
         updateMessageSearchResultSQL,
         "Failed to update message search entry.");
 
     bindStringToSQL(messageID, *preparedSQL, 1);
     bindStringToSQL(processedContent, *preparedSQL, 2);
     bindResult = bindStringToSQL(originalMessageID, *preparedSQL, 3);
   }
 
   if (bindResult != SQLITE_OK) {
     std::stringstream error_message;
     error_message << "Failed to bind key to SQL statement. Details: "
                   << sqlite3_errstr(bindResult) << std::endl;
     throw std::runtime_error(error_message.str());
   }
 
   sqlite3_step(*preparedSQL);
 }
 
 void SQLiteQueryExecutor::rekeyMessage(std::string from, std::string to) const {
   static std::string rekeyMessageSQL =
       "UPDATE OR REPLACE messages "
       "SET id = ? "
       "WHERE id = ?";
   rekeyAllEntities(
       SQLiteQueryExecutor::getConnection(), rekeyMessageSQL, from, to);
 }
 
 void SQLiteQueryExecutor::removeAllMedia() const {
   static std::string removeAllMediaSQL = "DELETE FROM media;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllMediaSQL);
 }
 
 void SQLiteQueryExecutor::removeMediaForMessages(
     const std::vector<std::string> &msgIDs) const {
   if (!msgIDs.size()) {
     return;
   }
 
   std::stringstream removeMediaByKeysSQLStream;
   removeMediaByKeysSQLStream << "DELETE FROM media "
                                 "WHERE container IN "
                              << getSQLStatementArray(msgIDs.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeMediaByKeysSQLStream.str(),
       msgIDs);
 }
 
 void SQLiteQueryExecutor::removeMediaForMessage(std::string msgID) const {
   static std::string removeMediaByKeySQL =
       "DELETE FROM media "
       "WHERE container IN (?);";
   std::vector<std::string> keys = {msgID};
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(), removeMediaByKeySQL, keys);
 }
 
 void SQLiteQueryExecutor::removeMediaForThreads(
     const std::vector<std::string> &threadIDs) const {
   if (!threadIDs.size()) {
     return;
   }
 
   std::stringstream removeMediaByKeysSQLStream;
   removeMediaByKeysSQLStream << "DELETE FROM media "
                                 "WHERE thread IN "
                              << getSQLStatementArray(threadIDs.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeMediaByKeysSQLStream.str(),
       threadIDs);
 }
 
 void SQLiteQueryExecutor::replaceMedia(const Media &media) const {
   static std::string replaceMediaSQL =
       "REPLACE INTO media "
       "(id, container, thread, uri, type, extras) "
       "VALUES (?, ?, ?, ?, ?, ?)";
   replaceEntity<Media>(
       SQLiteQueryExecutor::getConnection(), replaceMediaSQL, media);
 }
 
 void SQLiteQueryExecutor::rekeyMediaContainers(std::string from, std::string to)
     const {
   static std::string rekeyMediaContainersSQL =
       "UPDATE media SET container = ? WHERE container = ?;";
   rekeyAllEntities(
       SQLiteQueryExecutor::getConnection(), rekeyMediaContainersSQL, from, to);
 }
 
 void SQLiteQueryExecutor::replaceMessageStoreThreads(
     const std::vector<MessageStoreThread> &threads) const {
   static std::string replaceMessageStoreThreadSQL =
       "REPLACE INTO message_store_threads "
       "(id, start_reached) "
       "VALUES (?, ?);";
 
   for (auto &thread : threads) {
     replaceEntity<MessageStoreThread>(
         SQLiteQueryExecutor::getConnection(),
         replaceMessageStoreThreadSQL,
         thread);
   }
 }
 
 void SQLiteQueryExecutor::removeAllMessageStoreThreads() const {
   static std::string removeAllMessageStoreThreadsSQL =
       "DELETE FROM message_store_threads;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllMessageStoreThreadsSQL);
 }
 
 void SQLiteQueryExecutor::removeMessageStoreThreads(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeMessageStoreThreadsByKeysSQLStream;
   removeMessageStoreThreadsByKeysSQLStream
       << "DELETE FROM message_store_threads "
          "WHERE id IN "
       << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeMessageStoreThreadsByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<MessageStoreThread>
 SQLiteQueryExecutor::getAllMessageStoreThreads() const {
   static std::string getAllMessageStoreThreadsSQL =
       "SELECT * "
       "FROM message_store_threads;";
   return getAllEntities<MessageStoreThread>(
       SQLiteQueryExecutor::getConnection(), getAllMessageStoreThreadsSQL);
 }
 
 std::vector<Thread> SQLiteQueryExecutor::getAllThreads() const {
   static std::string getAllThreadsSQL =
       "SELECT * "
       "FROM threads;";
   return getAllEntities<Thread>(
       SQLiteQueryExecutor::getConnection(), getAllThreadsSQL);
 };
 
 void SQLiteQueryExecutor::removeThreads(std::vector<std::string> ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeThreadsByKeysSQLStream;
   removeThreadsByKeysSQLStream << "DELETE FROM threads "
                                   "WHERE id IN "
                                << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeThreadsByKeysSQLStream.str(),
       ids);
 };
 
 void SQLiteQueryExecutor::replaceThread(const Thread &thread) const {
   static std::string replaceThreadSQL =
       "REPLACE INTO threads ("
       " id, type, name, description, color, creation_time, parent_thread_id,"
       " containing_thread_id, community, members, roles, current_user,"
       " source_message_id, replies_count, avatar, pinned_count, timestamps) "
       "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
 
   replaceEntity<Thread>(
       SQLiteQueryExecutor::getConnection(), replaceThreadSQL, thread);
 };
 
 void SQLiteQueryExecutor::removeAllThreads() const {
   static std::string removeAllThreadsSQL = "DELETE FROM threads;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllThreadsSQL);
 };
 
 void SQLiteQueryExecutor::replaceReport(const Report &report) const {
   static std::string replaceReportSQL =
       "REPLACE INTO reports (id, report) "
       "VALUES (?, ?);";
 
   replaceEntity<Report>(
       SQLiteQueryExecutor::getConnection(), replaceReportSQL, report);
 }
 
 void SQLiteQueryExecutor::removeAllReports() const {
   static std::string removeAllReportsSQL = "DELETE FROM reports;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllReportsSQL);
 }
 
 void SQLiteQueryExecutor::removeReports(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeReportsByKeysSQLStream;
   removeReportsByKeysSQLStream << "DELETE FROM reports "
                                   "WHERE id IN "
                                << getSQLStatementArray(ids.size()) << ";";
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeReportsByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<Report> SQLiteQueryExecutor::getAllReports() const {
   static std::string getAllReportsSQL =
       "SELECT * "
       "FROM reports;";
   return getAllEntities<Report>(
       SQLiteQueryExecutor::getConnection(), getAllReportsSQL);
 }
 
 void SQLiteQueryExecutor::setPersistStorageItem(
     std::string key,
     std::string item) const {
   static std::string replacePersistStorageItemSQL =
       "REPLACE INTO persist_storage (key, item) "
       "VALUES (?, ?);";
   PersistItem entry{
       key,
       item,
   };
   replaceEntity<PersistItem>(
       SQLiteQueryExecutor::getConnection(),
       replacePersistStorageItemSQL,
       entry);
 }
 
 void SQLiteQueryExecutor::removePersistStorageItem(std::string key) const {
   static std::string removePersistStorageItemByKeySQL =
       "DELETE FROM persist_storage "
       "WHERE key IN (?);";
   std::vector<std::string> keys = {key};
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removePersistStorageItemByKeySQL,
       keys);
 }
 
 std::string SQLiteQueryExecutor::getPersistStorageItem(std::string key) const {
   static std::string getPersistStorageItemByPrimaryKeySQL =
       "SELECT * "
       "FROM persist_storage "
       "WHERE key = ?;";
   std::unique_ptr<PersistItem> entry = getEntityByPrimaryKey<PersistItem>(
       SQLiteQueryExecutor::getConnection(),
       getPersistStorageItemByPrimaryKeySQL,
       key);
   return (entry == nullptr) ? "" : entry->item;
 }
 
 void SQLiteQueryExecutor::replaceUser(const UserInfo &userInfo) const {
   static std::string replaceUserSQL =
       "REPLACE INTO users (id, user_info) "
       "VALUES (?, ?);";
   replaceEntity<UserInfo>(
       SQLiteQueryExecutor::getConnection(), replaceUserSQL, userInfo);
 }
 
 void SQLiteQueryExecutor::removeAllUsers() const {
   static std::string removeAllUsersSQL = "DELETE FROM users;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllUsersSQL);
 }
 
 void SQLiteQueryExecutor::removeUsers(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeUsersByKeysSQLStream;
   removeUsersByKeysSQLStream << "DELETE FROM users "
                                 "WHERE id IN "
                              << getSQLStatementArray(ids.size()) << ";";
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeUsersByKeysSQLStream.str(),
       ids);
 }
 
 void SQLiteQueryExecutor::replaceKeyserver(
     const KeyserverInfo &keyserverInfo) const {
   static std::string replaceKeyserverSQL =
       "REPLACE INTO keyservers (id, keyserver_info) "
       "VALUES (:id, :keyserver_info);";
   replaceEntity<KeyserverInfo>(
       SQLiteQueryExecutor::getConnection(), replaceKeyserverSQL, keyserverInfo);
 
   static std::string replaceKeyserverSyncedSQL =
       "REPLACE INTO keyservers_synced (id, keyserver_info) "
       "VALUES (:id, :synced_keyserver_info);";
   replaceEntity<KeyserverInfo>(
       SQLiteQueryExecutor::getConnection(),
       replaceKeyserverSyncedSQL,
       keyserverInfo);
 }
 
 void SQLiteQueryExecutor::removeAllKeyservers() const {
   static std::string removeAllKeyserversSQL = "DELETE FROM keyservers;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllKeyserversSQL);
   static std::string removeAllKeyserversSyncedSQL =
       "DELETE FROM keyservers_synced;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllKeyserversSyncedSQL);
 }
 
 void SQLiteQueryExecutor::removeKeyservers(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   auto idArray = getSQLStatementArray(ids.size());
 
   std::stringstream removeKeyserversByKeysSQLStream;
   removeKeyserversByKeysSQLStream << "DELETE FROM keyservers "
                                      "WHERE id IN "
                                   << idArray << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeKeyserversByKeysSQLStream.str(),
       ids);
 
   std::stringstream removeKeyserversSyncedByKeysSQLStream;
   removeKeyserversSyncedByKeysSQLStream << "DELETE FROM keyservers_synced "
                                            "WHERE id IN "
                                         << idArray << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeKeyserversSyncedByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<KeyserverInfo> SQLiteQueryExecutor::getAllKeyservers() const {
   static std::string getAllKeyserversSQL =
       "SELECT "
       "  synced.id, "
       "  COALESCE(keyservers.keyserver_info, ''), "
       "  synced.keyserver_info "
       "FROM keyservers_synced synced "
       "LEFT JOIN keyservers "
       "  ON synced.id = keyservers.id;";
   return getAllEntities<KeyserverInfo>(
       SQLiteQueryExecutor::getConnection(), getAllKeyserversSQL);
 }
 
 std::vector<UserInfo> SQLiteQueryExecutor::getAllUsers() const {
   static std::string getAllUsersSQL =
       "SELECT * "
       "FROM users;";
   return getAllEntities<UserInfo>(
       SQLiteQueryExecutor::getConnection(), getAllUsersSQL);
 }
 
 void SQLiteQueryExecutor::replaceCommunity(
     const CommunityInfo &communityInfo) const {
   static std::string replaceCommunitySQL =
       "REPLACE INTO communities (id, community_info) "
       "VALUES (?, ?);";
   replaceEntity<CommunityInfo>(
       SQLiteQueryExecutor::getConnection(), replaceCommunitySQL, communityInfo);
 }
 
 void SQLiteQueryExecutor::removeAllCommunities() const {
   static std::string removeAllCommunitiesSQL = "DELETE FROM communities;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllCommunitiesSQL);
 }
 
 void SQLiteQueryExecutor::removeCommunities(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeCommunitiesByKeysSQLStream;
   removeCommunitiesByKeysSQLStream << "DELETE FROM communities "
                                       "WHERE id IN "
                                    << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeCommunitiesByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<CommunityInfo> SQLiteQueryExecutor::getAllCommunities() const {
   static std::string getAllCommunitiesSQL =
       "SELECT * "
       "FROM communities;";
   return getAllEntities<CommunityInfo>(
       SQLiteQueryExecutor::getConnection(), getAllCommunitiesSQL);
 }
 
 void SQLiteQueryExecutor::replaceIntegrityThreadHashes(
     const std::vector<IntegrityThreadHash> &threadHashes) const {
   static std::string replaceIntegrityThreadHashSQL =
       "REPLACE INTO integrity_store (id, thread_hash) "
       "VALUES (?, ?);";
   for (const IntegrityThreadHash &integrityThreadHash : threadHashes) {
     replaceEntity<IntegrityThreadHash>(
         SQLiteQueryExecutor::getConnection(),
         replaceIntegrityThreadHashSQL,
         integrityThreadHash);
   }
 }
 
 void SQLiteQueryExecutor::removeAllIntegrityThreadHashes() const {
   static std::string removeAllIntegrityThreadHashesSQL =
       "DELETE FROM integrity_store;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllIntegrityThreadHashesSQL);
 }
 
 void SQLiteQueryExecutor::removeIntegrityThreadHashes(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeIntegrityThreadHashesByKeysSQLStream;
   removeIntegrityThreadHashesByKeysSQLStream << "DELETE FROM integrity_store "
                                                 "WHERE id IN "
                                              << getSQLStatementArray(ids.size())
                                              << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeIntegrityThreadHashesByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<IntegrityThreadHash>
 SQLiteQueryExecutor::getAllIntegrityThreadHashes() const {
   static std::string getAllIntegrityThreadHashesSQL =
       "SELECT * "
       "FROM integrity_store;";
   return getAllEntities<IntegrityThreadHash>(
       SQLiteQueryExecutor::getConnection(), getAllIntegrityThreadHashesSQL);
 }
 
 void SQLiteQueryExecutor::replaceSyncedMetadataEntry(
     const SyncedMetadataEntry &syncedMetadataEntry) const {
   static std::string replaceSyncedMetadataEntrySQL =
       "REPLACE INTO synced_metadata (name, data) "
       "VALUES (?, ?);";
   replaceEntity<SyncedMetadataEntry>(
       SQLiteQueryExecutor::getConnection(),
       replaceSyncedMetadataEntrySQL,
       syncedMetadataEntry);
 }
 
 void SQLiteQueryExecutor::removeAllSyncedMetadata() const {
   static std::string removeAllSyncedMetadataSQL =
       "DELETE FROM synced_metadata;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllSyncedMetadataSQL);
 }
 
 void SQLiteQueryExecutor::removeSyncedMetadata(
     const std::vector<std::string> &names) const {
   if (!names.size()) {
     return;
   }
 
   std::stringstream removeSyncedMetadataByNamesSQLStream;
   removeSyncedMetadataByNamesSQLStream << "DELETE FROM synced_metadata "
                                           "WHERE name IN "
                                        << getSQLStatementArray(names.size())
                                        << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeSyncedMetadataByNamesSQLStream.str(),
       names);
 }
 
 std::vector<SyncedMetadataEntry>
 SQLiteQueryExecutor::getAllSyncedMetadata() const {
   static std::string getAllSyncedMetadataSQL =
       "SELECT * "
       "FROM synced_metadata;";
   return getAllEntities<SyncedMetadataEntry>(
       SQLiteQueryExecutor::getConnection(), getAllSyncedMetadataSQL);
 }
 
 std::optional<int>
 SQLiteQueryExecutor::getSyncedDatabaseVersion(sqlite3 *db) const {
   static std::string getDBVersionSyncedMetadataSQL =
       "SELECT * "
       "FROM synced_metadata "
       "WHERE name=\"db_version\";";
   std::vector<SyncedMetadataEntry> entries =
       getAllEntities<SyncedMetadataEntry>(db, getDBVersionSyncedMetadataSQL);
   for (auto &entry : entries) {
     return std::stoi(entry.data);
   }
   return std::nullopt;
 }
 
 void SQLiteQueryExecutor::replaceAuxUserInfo(
     const AuxUserInfo &userInfo) const {
   static std::string replaceAuxUserInfoSQL =
       "REPLACE INTO aux_users (id, aux_user_info) "
       "VALUES (?, ?);";
   replaceEntity<AuxUserInfo>(
       SQLiteQueryExecutor::getConnection(), replaceAuxUserInfoSQL, userInfo);
 }
 
 void SQLiteQueryExecutor::removeAllAuxUserInfos() const {
   static std::string removeAllAuxUserInfosSQL = "DELETE FROM aux_users;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllAuxUserInfosSQL);
 }
 
 void SQLiteQueryExecutor::removeAuxUserInfos(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeAuxUserInfosByKeysSQLStream;
   removeAuxUserInfosByKeysSQLStream << "DELETE FROM aux_users "
                                        "WHERE id IN "
                                     << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeAuxUserInfosByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<AuxUserInfo> SQLiteQueryExecutor::getAllAuxUserInfos() const {
   static std::string getAllAuxUserInfosSQL =
       "SELECT * "
       "FROM aux_users;";
   return getAllEntities<AuxUserInfo>(
       SQLiteQueryExecutor::getConnection(), getAllAuxUserInfosSQL);
 }
 
 void SQLiteQueryExecutor::replaceThreadActivityEntry(
     const ThreadActivityEntry &threadActivityEntry) const {
   static std::string replaceThreadActivityEntrySQL =
       "REPLACE INTO thread_activity (id, thread_activity_store_entry) "
       "VALUES (?, ?);";
   replaceEntity<ThreadActivityEntry>(
       SQLiteQueryExecutor::getConnection(),
       replaceThreadActivityEntrySQL,
       threadActivityEntry);
 }
 
 void SQLiteQueryExecutor::removeAllThreadActivityEntries() const {
   static std::string removeAllThreadActivityEntriesSQL =
       "DELETE FROM thread_activity;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllThreadActivityEntriesSQL);
 }
 
 void SQLiteQueryExecutor::removeThreadActivityEntries(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeThreadActivityEntriesByKeysSQLStream;
   removeThreadActivityEntriesByKeysSQLStream << "DELETE FROM thread_activity "
                                                 "WHERE id IN "
                                              << getSQLStatementArray(ids.size())
                                              << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeThreadActivityEntriesByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<ThreadActivityEntry>
 SQLiteQueryExecutor::getAllThreadActivityEntries() const {
   static std::string getAllThreadActivityEntriesSQL =
       "SELECT * "
       "FROM thread_activity;";
   return getAllEntities<ThreadActivityEntry>(
       SQLiteQueryExecutor::getConnection(), getAllThreadActivityEntriesSQL);
 }
 
 void SQLiteQueryExecutor::replaceEntry(const EntryInfo &entryInfo) const {
   static std::string replaceEntrySQL =
       "REPLACE INTO entries (id, entry) "
       "VALUES (?, ?);";
   replaceEntity<EntryInfo>(
       SQLiteQueryExecutor::getConnection(), replaceEntrySQL, entryInfo);
 }
 
 void SQLiteQueryExecutor::removeAllEntries() const {
   static std::string removeAllEntriesSQL = "DELETE FROM entries;";
   removeAllEntities(SQLiteQueryExecutor::getConnection(), removeAllEntriesSQL);
 }
 
 void SQLiteQueryExecutor::removeEntries(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeEntriesByKeysSQLStream;
   removeEntriesByKeysSQLStream << "DELETE FROM entries "
                                   "WHERE id IN "
                                << getSQLStatementArray(ids.size()) << ";";
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeEntriesByKeysSQLStream.str(),
       ids);
 }
 
 std::vector<EntryInfo> SQLiteQueryExecutor::getAllEntries() const {
   static std::string getAllEntriesSQL =
       "SELECT * "
       "FROM entries;";
   return getAllEntities<EntryInfo>(
       SQLiteQueryExecutor::getConnection(), getAllEntriesSQL);
 }
 
 void SQLiteQueryExecutor::replaceMessageStoreLocalMessageInfo(
     const LocalMessageInfo &localMessageInfo) const {
   static std::string replaceLocalMessageInfoSQL =
       "REPLACE INTO message_store_local (id, local_message_info) "
       "VALUES (?, ?);";
   replaceEntity<LocalMessageInfo>(
       SQLiteQueryExecutor::getConnection(),
       replaceLocalMessageInfoSQL,
       localMessageInfo);
 }
 
 void SQLiteQueryExecutor::removeMessageStoreLocalMessageInfos(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeLocalMessageInfosByKeysSQLStream;
   removeLocalMessageInfosByKeysSQLStream << "DELETE FROM message_store_local "
                                             "WHERE id IN "
                                          << getSQLStatementArray(ids.size())
                                          << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(),
       removeLocalMessageInfosByKeysSQLStream.str(),
       ids);
 }
 
 void SQLiteQueryExecutor::removeAllMessageStoreLocalMessageInfos() const {
   static std::string removeAllLocalMessageInfosSQL =
       "DELETE FROM message_store_local;";
   removeAllEntities(
       SQLiteQueryExecutor::getConnection(), removeAllLocalMessageInfosSQL);
 }
 
 std::vector<LocalMessageInfo>
 SQLiteQueryExecutor::getAllMessageStoreLocalMessageInfos() const {
   static std::string getAllLocalMessageInfosSQL =
       "SELECT * "
       "FROM message_store_local;";
   return getAllEntities<LocalMessageInfo>(
       SQLiteQueryExecutor::getConnection(), getAllLocalMessageInfosSQL);
 }
 
 void SQLiteQueryExecutor::beginTransaction() const {
   executeQuery(SQLiteQueryExecutor::getConnection(), "BEGIN TRANSACTION;");
 }
 
 void SQLiteQueryExecutor::commitTransaction() const {
   executeQuery(SQLiteQueryExecutor::getConnection(), "COMMIT;");
 }
 
 void SQLiteQueryExecutor::rollbackTransaction() const {
   executeQuery(SQLiteQueryExecutor::getConnection(), "ROLLBACK;");
 }
 
 int SQLiteQueryExecutor::getContentAccountID() const {
   return CONTENT_ACCOUNT_ID;
 }
 
 int SQLiteQueryExecutor::getNotifsAccountID() const {
   return NOTIFS_ACCOUNT_ID;
 }
 
 std::vector<OlmPersistSession>
 SQLiteQueryExecutor::getOlmPersistSessionsData() const {
   static std::string getAllOlmPersistSessionsSQL =
       "SELECT * "
       "FROM olm_persist_sessions;";
   return getAllEntities<OlmPersistSession>(
       SQLiteQueryExecutor::getConnection(), getAllOlmPersistSessionsSQL);
 }
 
 std::optional<std::string>
 SQLiteQueryExecutor::getOlmPersistAccountData(int accountID) const {
   static std::string getOlmPersistAccountSQL =
       "SELECT * "
       "FROM olm_persist_account "
       "WHERE id = ?;";
   std::unique_ptr<OlmPersistAccount> result =
       getEntityByIntegerPrimaryKey<OlmPersistAccount>(
           SQLiteQueryExecutor::getConnection(),
           getOlmPersistAccountSQL,
           accountID);
   if (result == nullptr) {
     return std::nullopt;
   }
   return result->account_data;
 }
 
 void SQLiteQueryExecutor::storeOlmPersistAccount(
     int accountID,
     const std::string &accountData) const {
   static std::string replaceOlmPersistAccountSQL =
       "REPLACE INTO olm_persist_account (id, account_data) "
       "VALUES (?, ?);";
 
   OlmPersistAccount persistAccount = {accountID, accountData};
 
   replaceEntity<OlmPersistAccount>(
       SQLiteQueryExecutor::getConnection(),
       replaceOlmPersistAccountSQL,
       persistAccount);
 }
 
 void SQLiteQueryExecutor::storeOlmPersistSession(
     const OlmPersistSession &session) const {
   static std::string replaceOlmPersistSessionSQL =
       "REPLACE INTO olm_persist_sessions "
       "(target_device_id, session_data, version) "
       "VALUES (?, ?, ?);";
 
   replaceEntity<OlmPersistSession>(
       SQLiteQueryExecutor::getConnection(),
       replaceOlmPersistSessionSQL,
       session);
 }
 
 void SQLiteQueryExecutor::storeOlmPersistData(
     int accountID,
     crypto::Persist persist) const {
 
   if (accountID != CONTENT_ACCOUNT_ID && persist.sessions.size() > 0) {
     throw std::runtime_error(
         "Attempt to store notifications sessions in SQLite. Notifications "
         "sessions must be stored in storage shared with NSE.");
   }
 
   std::string accountData =
       std::string(persist.account.begin(), persist.account.end());
   this->storeOlmPersistAccount(accountID, accountData);
 
   for (auto it = persist.sessions.begin(); it != persist.sessions.end(); it++) {
     OlmPersistSession persistSession = {
         it->first,
         std::string(it->second.buffer.begin(), it->second.buffer.end()),
         it->second.version};
 
     this->storeOlmPersistSession(persistSession);
   }
 }
 
 void SQLiteQueryExecutor::setNotifyToken(std::string token) const {
   this->setMetadata("notify_token", token);
 }
 
 void SQLiteQueryExecutor::clearNotifyToken() const {
   this->clearMetadata("notify_token");
 }
 
 void SQLiteQueryExecutor::stampSQLiteDBUserID(std::string userID) const {
   this->setMetadata("current_user_id", userID);
 }
 
 std::string SQLiteQueryExecutor::getSQLiteStampedUserID() const {
   return this->getMetadata("current_user_id");
 }
 
 void SQLiteQueryExecutor::setMetadata(std::string entryName, std::string data)
     const {
   std::string replaceMetadataSQL =
       "REPLACE INTO metadata (name, data) "
       "VALUES (?, ?);";
   Metadata entry{
       entryName,
       data,
   };
   replaceEntity<Metadata>(
       SQLiteQueryExecutor::getConnection(), replaceMetadataSQL, entry);
 }
 
 void SQLiteQueryExecutor::clearMetadata(std::string entryName) const {
   static std::string removeMetadataByKeySQL =
       "DELETE FROM metadata "
       "WHERE name IN (?);";
   std::vector<std::string> keys = {entryName};
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(), removeMetadataByKeySQL, keys);
 }
 
 std::string SQLiteQueryExecutor::getMetadata(std::string entryName) const {
   std::string getMetadataByPrimaryKeySQL =
       "SELECT * "
       "FROM metadata "
       "WHERE name = ?;";
   std::unique_ptr<Metadata> entry = getEntityByPrimaryKey<Metadata>(
       SQLiteQueryExecutor::getConnection(),
       getMetadataByPrimaryKeySQL,
       entryName);
   return (entry == nullptr) ? "" : entry->data;
 }
 
 void SQLiteQueryExecutor::addOutboundP2PMessages(
     const std::vector<OutboundP2PMessage> &messages) const {
   static std::string addMessage =
       "REPLACE INTO outbound_p2p_messages ("
       " message_id, device_id, user_id, timestamp,"
       " plaintext, ciphertext, status, supports_auto_retry) "
       "VALUES (?, ?, ?, ?, ?, ?, ?, ?);";
 
   for (const OutboundP2PMessage &clientMessage : messages) {
     SQLiteOutboundP2PMessage message =
         clientMessage.toSQLiteOutboundP2PMessage();
     replaceEntity<SQLiteOutboundP2PMessage>(
         SQLiteQueryExecutor::getConnection(), addMessage, message);
   }
 }
 
 std::vector<OutboundP2PMessage> SQLiteQueryExecutor::getOutboundP2PMessagesByID(
     const std::vector<std::string> &ids) const {
   std::stringstream getOutboundP2PMessageSQLStream;
   getOutboundP2PMessageSQLStream << "SELECT * "
                                     "FROM outbound_p2p_messages "
                                     "WHERE message_id IN "
                                  << getSQLStatementArray(ids.size()) << ";";
   std::string getOutboundP2PMessageSQL = getOutboundP2PMessageSQLStream.str();
 
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       getOutboundP2PMessageSQL,
       "Failed to get outbound messages by ID");
 
   std::vector<SQLiteOutboundP2PMessage> queryResult =
       getAllEntitiesByPrimaryKeys<SQLiteOutboundP2PMessage>(
           SQLiteQueryExecutor::getConnection(), getOutboundP2PMessageSQL, ids);
   std::vector<OutboundP2PMessage> result;
   for (auto &message : queryResult) {
     result.emplace_back(OutboundP2PMessage(message));
   }
   return result;
 }
 
 std::vector<OutboundP2PMessage>
 SQLiteQueryExecutor::getUnsentOutboundP2PMessages() const {
   std::string query =
       "SELECT * FROM outbound_p2p_messages "
       "WHERE status != 'sent' "
       "ORDER BY timestamp;";
 
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       query,
       "Failed to get all messages to device");
 
   std::vector<OutboundP2PMessage> messages;
   for (int stepResult = sqlite3_step(preparedSQL); stepResult == SQLITE_ROW;
        stepResult = sqlite3_step(preparedSQL)) {
     messages.emplace_back(OutboundP2PMessage(
         SQLiteOutboundP2PMessage::fromSQLResult(preparedSQL, 0)));
   }
 
   return messages;
 }
 
 void SQLiteQueryExecutor::removeOutboundP2PMessage(
     std::string confirmedMessageID,
     std::string deviceID) const {
   std::string query =
       "DELETE FROM outbound_p2p_messages "
       "WHERE message_id = ? AND device_id = ?;";
 
   comm::SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       query,
       "Failed to remove messages to device");
 
   bindStringToSQL(confirmedMessageID.c_str(), preparedSQL, 1);
   bindStringToSQL(deviceID.c_str(), preparedSQL, 2);
 
   sqlite3_step(preparedSQL);
 }
 
 void SQLiteQueryExecutor::removeAllOutboundP2PMessages(
     const std::string &deviceID) const {
   static std::string removeMessagesSQL =
       "DELETE FROM outbound_p2p_messages "
       "WHERE device_id IN (?);";
   std::vector<std::string> keys = {deviceID};
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(), removeMessagesSQL, keys);
 }
 
 void SQLiteQueryExecutor::setCiphertextForOutboundP2PMessage(
     std::string messageID,
     std::string deviceID,
     std::string ciphertext) const {
   static std::string query =
       "UPDATE outbound_p2p_messages "
       "SET ciphertext = ?, status = 'encrypted' "
       "WHERE message_id = ? AND device_id = ?;";
 
   comm::SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       query,
       "Failed to set ciphertext for OutboundP2PMessage");
 
   bindStringToSQL(ciphertext.c_str(), preparedSQL, 1);
   bindStringToSQL(messageID.c_str(), preparedSQL, 2);
   bindStringToSQL(deviceID.c_str(), preparedSQL, 3);
 
   sqlite3_step(preparedSQL);
 }
 
 void SQLiteQueryExecutor::markOutboundP2PMessageAsSent(
     std::string messageID,
     std::string deviceID) const {
   static std::string query =
       "UPDATE outbound_p2p_messages "
       "SET status = 'sent' "
       "WHERE message_id = ? AND device_id = ?;";
 
   comm::SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       query,
       "Failed to mark OutboundP2PMessage as sent");
 
   bindStringToSQL(messageID.c_str(), preparedSQL, 1);
   bindStringToSQL(deviceID.c_str(), preparedSQL, 2);
 
   sqlite3_step(preparedSQL);
 }
 
 std::vector<std::string> SQLiteQueryExecutor::resetOutboundP2PMessagesForDevice(
     std::string deviceID) const {
   // Query all messages that need to be resent - all message that supports
   // auto retry or already sent messages.
   std::string queryMessageIDsToResend =
       "SELECT message_id "
       "FROM outbound_p2p_messages "
       "WHERE device_id = ? AND ( "
       "  supports_auto_retry = 1 "
       "  OR (supports_auto_retry = 0 AND status = 'sent') "
       ");";
 
   SQLiteStatementWrapper preparedQueryMessageIDsSQL(
       SQLiteQueryExecutor::getConnection(),
       queryMessageIDsToResend,
       "Failed to get all messages to reset");
 
   bindStringToSQL(deviceID.c_str(), preparedQueryMessageIDsSQL, 1);
   std::vector<std::string> messageIDs;
   for (int stepResult = sqlite3_step(preparedQueryMessageIDsSQL);
        stepResult == SQLITE_ROW;
        stepResult = sqlite3_step(preparedQueryMessageIDsSQL)) {
     messageIDs.push_back(getStringFromSQLRow(preparedQueryMessageIDsSQL, 0));
   }
 
   // Setting ciphertext to an empty string to make sure this message will be
   // encrypted again with a new session, update the status, and set
   // supports_auto_retry to true.
   // Updating supports_auto_retry to true because those are already sent
   // messages (from the UI perspective), but the recipient failed to decrypt
   // so needs to be automatically resent.
   std::stringstream resetMessagesSQLStream;
   resetMessagesSQLStream
       << "UPDATE outbound_p2p_messages "
       << "SET supports_auto_retry = 1, status = 'persisted', ciphertext = '' "
       << "WHERE message_id IN " << getSQLStatementArray(messageIDs.size())
       << ";";
 
   SQLiteStatementWrapper preparedUpdateSQL(
       SQLiteQueryExecutor::getConnection(),
       resetMessagesSQLStream.str(),
       "Failed to reset messages.");
 
   for (int i = 0; i < messageIDs.size(); i++) {
     int bindResult = bindStringToSQL(messageIDs[i], preparedUpdateSQL, i + 1);
     if (bindResult != SQLITE_OK) {
       std::stringstream error_message;
       error_message << "Failed to bind key to SQL statement. Details: "
                     << sqlite3_errstr(bindResult) << std::endl;
       sqlite3_finalize(preparedUpdateSQL);
       throw std::runtime_error(error_message.str());
     }
   }
   sqlite3_step(preparedUpdateSQL);
 
   // This handles the case of messages that are encrypted (with a malformed
   // session) but not yet queued on Tunnelbroker. In this case, this message
   // is not considered to be sent (from the UI perspective),
   // and supports_auto_retry is not updated.
   std::string updateCiphertextQuery =
       "UPDATE outbound_p2p_messages "
       "SET ciphertext = '', status = 'persisted'"
       "WHERE device_id = ? "
       "  AND supports_auto_retry = 0 "
       "  AND status = 'encrypted';";
 
   SQLiteStatementWrapper preparedUpdateCiphertextSQL(
       SQLiteQueryExecutor::getConnection(),
       updateCiphertextQuery,
       "Failed to set ciphertext");
 
   bindStringToSQL(deviceID.c_str(), preparedUpdateCiphertextSQL, 1);
   sqlite3_step(preparedUpdateCiphertextSQL);
 
   return messageIDs;
 }
 
 void SQLiteQueryExecutor::addInboundP2PMessage(
     InboundP2PMessage message) const {
   static std::string addMessage =
       "REPLACE INTO inbound_p2p_messages ("
       "  message_id, sender_device_id, plaintext, status, sender_user_id)"
       "VALUES (?, ?, ?, ?, ?);";
 
   replaceEntity<InboundP2PMessage>(
       SQLiteQueryExecutor::getConnection(), addMessage, message);
 }
 
 std::vector<InboundP2PMessage>
 SQLiteQueryExecutor::getAllInboundP2PMessage() const {
   static std::string query =
       "SELECT message_id, sender_device_id, plaintext, status, sender_user_id "
       "FROM inbound_p2p_messages;";
   return getAllEntities<InboundP2PMessage>(
       SQLiteQueryExecutor::getConnection(), query);
 }
 
 void SQLiteQueryExecutor::removeInboundP2PMessages(
     const std::vector<std::string> &ids) const {
   if (!ids.size()) {
     return;
   }
 
   std::stringstream removeMessagesSQLStream;
   removeMessagesSQLStream << "DELETE FROM inbound_p2p_messages "
                              "WHERE message_id IN "
                           << getSQLStatementArray(ids.size()) << ";";
 
   removeEntitiesByKeys(
       SQLiteQueryExecutor::getConnection(), removeMessagesSQLStream.str(), ids);
 }
 
 std::vector<InboundP2PMessage> SQLiteQueryExecutor::getInboundP2PMessagesByID(
     const std::vector<std::string> &ids) const {
   std::stringstream getInboundP2PMessagesSQLStream;
   getInboundP2PMessagesSQLStream << "SELECT "
                                     "  message_id, sender_device_id, "
                                     "  plaintext, status, sender_user_id "
                                     "FROM inbound_p2p_messages "
                                     "WHERE message_id IN "
                                  << getSQLStatementArray(ids.size()) << ";";
   std::string getInboundP2PMessageSQL = getInboundP2PMessagesSQLStream.str();
 
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       getInboundP2PMessageSQL,
       "Failed to get inbound messages by ID");
 
   return getAllEntitiesByPrimaryKeys<InboundP2PMessage>(
       SQLiteQueryExecutor::getConnection(), getInboundP2PMessageSQL, ids);
 }
 
 std::vector<MessageEntity>
 SQLiteQueryExecutor::getRelatedMessages(const std::string &messageID) const {
   static std::string getMessageSQL =
       "SELECT "
       "  m.id, m.local_id, m.thread, m.user, m.type, m.future_type, "
       "  m.content, m.time, media.id, media.container, media.thread, "
       "  media.uri, media.type, media.extras "
       "FROM messages AS m "
       "LEFT JOIN media "
       "  ON m.id = media.container "
       "WHERE m.id = ? OR m.target_message = ? "
       "ORDER BY m.time DESC";
   comm::SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       getMessageSQL,
       "Failed to get latest message edit");
   bindStringToSQL(messageID.c_str(), preparedSQL, 1);
   bindStringToSQL(messageID.c_str(), preparedSQL, 2);
   return this->processMessagesResults(preparedSQL);
 }
 
 std::vector<MessageEntity> SQLiteQueryExecutor::searchMessages(
     std::string query,
     std::string threadID,
     std::optional<std::string> timestampCursor,
     std::optional<std::string> messageIDCursor) const {
   std::stringstream searchMessagesSQL;
   searchMessagesSQL
       << "SELECT "
          "  m.id, m.local_id, m.thread, m.user, m.type, m.future_type, "
          "  m.content, m.time, media.id, media.container, media.thread, "
          "  media.uri, media.type, media.extras "
          "FROM message_search AS s "
          "LEFT JOIN messages AS m "
          "  ON m.id = s.original_message_id "
          "LEFT JOIN media "
          "  ON m.id = media.container "
          "LEFT JOIN messages AS m2 "
          "  ON m2.target_message = m.id "
          "  AND m2.type = ? AND m2.thread = ? "
          "WHERE s.processed_content MATCH ? "
          "  AND (m.thread = ? OR m2.id IS NOT NULL) ";
 
   bool usingCursor = timestampCursor.has_value() && messageIDCursor.has_value();
 
   if (usingCursor) {
     searchMessagesSQL << " AND (m.time < ? OR (m.time = ? AND m.id < ?)) ";
   }
   searchMessagesSQL << "ORDER BY m.time DESC, m.id DESC "
                     << "LIMIT 20;";
 
   comm::SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       searchMessagesSQL.str(),
       "Failed to get message search results");
 
   auto sidebarSourceType = static_cast<int>(MessageType::SIDEBAR_SOURCE);
 
   bindIntToSQL(sidebarSourceType, preparedSQL, 1);
   bindStringToSQL(threadID.c_str(), preparedSQL, 2);
   bindStringToSQL(query.c_str(), preparedSQL, 3);
   bindStringToSQL(threadID.c_str(), preparedSQL, 4);
 
   if (usingCursor) {
     int64_t timestamp = std::stoll(timestampCursor.value());
     bindInt64ToSQL(timestamp, preparedSQL, 5);
     bindInt64ToSQL(timestamp, preparedSQL, 6);
     bindStringToSQL(messageIDCursor.value(), preparedSQL, 7);
   }
 
   std::vector<MessageEntity> messages =
       this->processMessagesResults(preparedSQL);
   std::vector<std::string> messageIDs;
   for (const auto &message : messages) {
     messageIDs.push_back(message.first.id);
   }
   std::vector<MessageEntity> relatedMessages =
       this->getRelatedMessagesForSearch(messageIDs);
 
   for (auto &entity : relatedMessages) {
     messages.push_back(std::move(entity));
   }
   return messages;
 }
 
 std::vector<MessageEntity> SQLiteQueryExecutor::getRelatedMessagesForSearch(
     const std::vector<std::string> &messageIDs) const {
   std::stringstream selectRelatedMessagesSQLStream;
   selectRelatedMessagesSQLStream << "SELECT "
                                     "  m.id, m.local_id, m.thread, m.user, "
                                     "  m.type, m.future_type, m.content, "
                                     "  m.time, media.id, media.container, "
                                     "  media.thread, media.uri, media.type, "
                                     "  media.extras "
                                     "FROM messages AS m "
                                     "LEFT JOIN media "
                                     "  ON m.id = media.container "
                                     "WHERE m.target_message IN "
                                  << getSQLStatementArray(messageIDs.size())
                                  << "ORDER BY m.time DESC";
 
   std::string selectRelatedMessagesSQL = selectRelatedMessagesSQLStream.str();
 
   SQLiteStatementWrapper preparedSQL(
       SQLiteQueryExecutor::getConnection(),
       selectRelatedMessagesSQL,
       "Failed to fetch related messages.");
 
   for (int i = 0; i < messageIDs.size(); i++) {
     int bindResult = bindStringToSQL(messageIDs[i], preparedSQL, i + 1);
     if (bindResult != SQLITE_OK) {
       std::stringstream error_message;
       error_message << "Failed to bind key to SQL statement. Details: "
                     << sqlite3_errstr(bindResult) << std::endl;
       sqlite3_finalize(preparedSQL);
       throw std::runtime_error(error_message.str());
     }
   }
 
   return this->processMessagesResults(preparedSQL);
 }
 
+void SQLiteQueryExecutor::replaceDMOperation(
+    const DMOperation &operation) const {
+  static std::string query =
+      "REPLACE INTO dm_operations (id, type, operation) "
+      "VALUES (?, ?, ?);";
+  replaceEntity<DMOperation>(
+      SQLiteQueryExecutor::getConnection(), query, operation);
+}
+
+void SQLiteQueryExecutor::removeAllDMOperations() const {
+  static std::string query = "DELETE FROM dm_operations;";
+  removeAllEntities(SQLiteQueryExecutor::getConnection(), query);
+}
+
+void SQLiteQueryExecutor::removeDMOperations(
+    const std::vector<std::string> &ids) const {
+  if (!ids.size()) {
+    return;
+  }
+
+  std::stringstream queryStream;
+  queryStream << "DELETE FROM dm_operations "
+                 "WHERE id IN "
+              << getSQLStatementArray(ids.size()) << ";";
+  removeEntitiesByKeys(
+      SQLiteQueryExecutor::getConnection(), queryStream.str(), ids);
+}
+
+std::vector<DMOperation> SQLiteQueryExecutor::getDMOperations() const {
+  static std::string query =
+      "SELECT id, type, operation "
+      "FROM dm_operations;";
+  return getAllEntities<DMOperation>(
+      SQLiteQueryExecutor::getConnection(), query);
+}
+
+std::vector<DMOperation> SQLiteQueryExecutor::getDMOperationsByType(
+    const std::string &operationType) const {
+  static std::string query =
+      "SELECT id, type, operation "
+      "FROM dm_operations "
+      "WHERE type = ?;";
+
+  std::vector<std::string> types{operationType};
+  return getAllEntitiesByPrimaryKeys<DMOperation>(
+      SQLiteQueryExecutor::getConnection(), query, types);
+}
+
 #ifdef EMSCRIPTEN
 std::vector<WebThread> SQLiteQueryExecutor::getAllThreadsWeb() const {
   auto threads = this->getAllThreads();
   std::vector<WebThread> webThreads;
   webThreads.reserve(threads.size());
   for (const auto &thread : threads) {
     webThreads.emplace_back(thread);
   }
   return webThreads;
 };
 
 void SQLiteQueryExecutor::replaceThreadWeb(const WebThread &thread) const {
   this->replaceThread(thread.toThread());
 };
 
 std::vector<MessageWithMedias> SQLiteQueryExecutor::transformToWebMessages(
     const std::vector<MessageEntity> &messages) const {
   std::vector<MessageWithMedias> messageWithMedias;
   for (auto &messageWithMedia : messages) {
     messageWithMedias.push_back(
         {std::move(messageWithMedia.first), messageWithMedia.second});
   }
 
   return messageWithMedias;
 }
 
 std::vector<MessageWithMedias>
 SQLiteQueryExecutor::getInitialMessagesWeb() const {
   auto messages = this->getInitialMessages();
   return this->transformToWebMessages(messages);
 }
 
 std::vector<MessageWithMedias> SQLiteQueryExecutor::fetchMessagesWeb(
     std::string threadID,
     int limit,
     int offset) const {
   auto messages = this->fetchMessages(threadID, limit, offset);
   return this->transformToWebMessages(messages);
 }
 
 void SQLiteQueryExecutor::replaceMessageWeb(const WebMessage &message) const {
   this->replaceMessage(message.toMessage());
 };
 
 NullableString
 SQLiteQueryExecutor::getOlmPersistAccountDataWeb(int accountID) const {
   std::optional<std::string> accountData =
       this->getOlmPersistAccountData(accountID);
   if (!accountData.has_value()) {
     return NullableString();
   }
   return std::make_unique<std::string>(accountData.value());
 }
 
 std::vector<MessageWithMedias>
 SQLiteQueryExecutor::getRelatedMessagesWeb(const std::string &messageID) const {
   auto relatedMessages = this->getRelatedMessages(messageID);
   return this->transformToWebMessages(relatedMessages);
 }
 
 std::vector<MessageWithMedias> SQLiteQueryExecutor::searchMessagesWeb(
     std::string query,
     std::string threadID,
     std::optional<std::string> timestampCursor,
     std::optional<std::string> messageIDCursor) const {
   auto messages =
       this->searchMessages(query, threadID, timestampCursor, messageIDCursor);
   return this->transformToWebMessages(messages);
 }
 #else
 void SQLiteQueryExecutor::clearSensitiveData() {
   SQLiteQueryExecutor::closeConnection();
   if (file_exists(SQLiteQueryExecutor::sqliteFilePath) &&
       std::remove(SQLiteQueryExecutor::sqliteFilePath.c_str())) {
     std::ostringstream errorStream;
     errorStream << "Failed to delete database file. Details: "
                 << strerror(errno);
     throw std::system_error(errno, std::generic_category(), errorStream.str());
   }
   SQLiteQueryExecutor::generateBackupDataKey();
   SQLiteQueryExecutor::migrate();
 }
 
 void SQLiteQueryExecutor::initialize(std::string &databasePath) {
   std::call_once(SQLiteQueryExecutor::initialized, [&databasePath]() {
     SQLiteQueryExecutor::sqliteFilePath = databasePath;
     folly::Optional<std::string> maybeBackupDataKey =
         CommSecureStore::get(CommSecureStore::backupDataKey);
     folly::Optional<std::string> maybeBackupLogDataKey =
         CommSecureStore::get(CommSecureStore::backupLogDataKey);
 
     if (file_exists(databasePath) && maybeBackupDataKey &&
         maybeBackupLogDataKey) {
       SQLiteQueryExecutor::backupDataKey = maybeBackupDataKey.value();
       SQLiteQueryExecutor::backupLogDataKey = maybeBackupLogDataKey.value();
       return;
     } else if (file_exists(databasePath) && maybeBackupDataKey) {
       SQLiteQueryExecutor::backupDataKey = maybeBackupDataKey.value();
       SQLiteQueryExecutor::generateBackupLogDataKey();
       return;
     }
     SQLiteQueryExecutor::generateBackupDataKey();
   });
 }
 
 void SQLiteQueryExecutor::initializeTablesForLogMonitoring() {
   sqlite3 *db;
   sqlite3_open(SQLiteQueryExecutor::sqliteFilePath.c_str(), &db);
   default_on_db_open_callback(db);
 
   std::vector<std::string> tablesToMonitor;
   {
     SQLiteStatementWrapper preparedSQL(
         db,
         "SELECT name FROM sqlite_master WHERE type='table';",
         "Failed to get all database tables");
 
     for (int stepResult = sqlite3_step(preparedSQL); stepResult == SQLITE_ROW;
          stepResult = sqlite3_step(preparedSQL)) {
       std::string table_name =
           reinterpret_cast<const char *>(sqlite3_column_text(preparedSQL, 0));
       if (SQLiteQueryExecutor::backedUpTablesBlocklist.find(table_name) ==
           SQLiteQueryExecutor::backedUpTablesBlocklist.end()) {
         tablesToMonitor.emplace_back(table_name);
       }
     }
     // Runs preparedSQL destructor which finalizes the sqlite statement
   }
   sqlite3_close(db);
 
   SQLiteQueryExecutor::connectionManager.tablesToMonitor = tablesToMonitor;
 }
 
 void SQLiteQueryExecutor::createMainCompaction(std::string backupID) const {
   std::string finalBackupPath =
       PlatformSpecificTools::getBackupFilePath(backupID, false);
   std::string finalAttachmentsPath =
       PlatformSpecificTools::getBackupFilePath(backupID, true);
 
   std::string tempBackupPath = finalBackupPath + "_tmp";
   std::string tempAttachmentsPath = finalAttachmentsPath + "_tmp";
 
   if (file_exists(tempBackupPath)) {
     Logger::log(
         "Attempting to delete temporary backup file from previous backup "
         "attempt.");
     attempt_delete_file(
         tempBackupPath,
         "Failed to delete temporary backup file from previous backup "
         "attempt.");
   }
 
   if (file_exists(tempAttachmentsPath)) {
     Logger::log(
         "Attempting to delete temporary attachments file from previous "
         "backup "
         "attempt.");
     attempt_delete_file(
         tempAttachmentsPath,
         "Failed to delete temporary attachments file from previous backup "
         "attempt.");
   }
 
   sqlite3 *backupDB;
   sqlite3_open(tempBackupPath.c_str(), &backupDB);
   set_encryption_key(backupDB);
 
   sqlite3_backup *backupObj = sqlite3_backup_init(
       backupDB, "main", SQLiteQueryExecutor::getConnection(), "main");
   if (!backupObj) {
     std::stringstream error_message;
     error_message << "Failed to init backup for main compaction. Details: "
                   << sqlite3_errmsg(backupDB) << std::endl;
     sqlite3_close(backupDB);
     throw std::runtime_error(error_message.str());
   }
 
   int backupResult = sqlite3_backup_step(backupObj, -1);
   sqlite3_backup_finish(backupObj);
   if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) {
     sqlite3_close(backupDB);
     throw std::runtime_error(
         "Programmer error. Database in transaction during backup attempt.");
   } else if (backupResult != SQLITE_DONE) {
     sqlite3_close(backupDB);
     std::stringstream error_message;
     error_message << "Failed to create database backup. Details: "
                   << sqlite3_errstr(backupResult);
     throw std::runtime_error(error_message.str());
   }
 
   if (!SQLiteQueryExecutor::backedUpTablesBlocklist.empty()) {
     std::string removeDeviceSpecificDataSQL = "";
     for (const auto &table_name :
          SQLiteQueryExecutor::backedUpTablesBlocklist) {
       removeDeviceSpecificDataSQL.append("DELETE FROM " + table_name + ";\n");
     }
     executeQuery(backupDB, removeDeviceSpecificDataSQL);
   }
 
   executeQuery(backupDB, "VACUUM;");
   sqlite3_close(backupDB);
 
   attempt_rename_file(
       tempBackupPath,
       finalBackupPath,
       "Failed to rename complete temporary backup file to final backup "
       "file.");
 
   std::ofstream tempAttachmentsFile(tempAttachmentsPath);
   if (!tempAttachmentsFile.is_open()) {
     throw std::runtime_error(
         "Unable to create attachments file for backup id: " + backupID);
   }
 
   std::string getAllBlobServiceMediaSQL =
       "SELECT * FROM media WHERE uri LIKE 'comm-blob-service://%';";
   std::vector<Media> blobServiceMedia = getAllEntities<Media>(
       SQLiteQueryExecutor::getConnection(), getAllBlobServiceMediaSQL);
 
   for (const auto &media : blobServiceMedia) {
     std::string blobServiceURI = media.uri;
     std::string blobHash = blob_hash_from_blob_service_uri(blobServiceURI);
     tempAttachmentsFile << blobHash << "\n";
   }
   tempAttachmentsFile.close();
 
   attempt_rename_file(
       tempAttachmentsPath,
       finalAttachmentsPath,
       "Failed to rename complete temporary attachments file to final "
       "attachments file.");
 
   this->setMetadata("backupID", backupID);
   this->clearMetadata("logID");
   if (StaffUtils::isStaffRelease()) {
     SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true);
   }
 }
 
 void SQLiteQueryExecutor::generateBackupDataKey() {
   std::string backupDataKey = comm::crypto::Tools::generateRandomHexString(
       SQLiteQueryExecutor::backupDataKeySize);
   CommSecureStore::set(CommSecureStore::backupDataKey, backupDataKey);
   SQLiteQueryExecutor::backupDataKey = backupDataKey;
   SQLiteQueryExecutor::generateBackupLogDataKey();
 }
 
 void SQLiteQueryExecutor::generateBackupLogDataKey() {
   std::string backupLogDataKey = comm::crypto::Tools::generateRandomHexString(
       SQLiteQueryExecutor::backupLogDataKeySize);
   CommSecureStore::set(CommSecureStore::backupLogDataKey, backupLogDataKey);
   SQLiteQueryExecutor::backupLogDataKey = backupLogDataKey;
 }
 
 void SQLiteQueryExecutor::captureBackupLogs() const {
   std::string backupID = this->getMetadata("backupID");
   if (!backupID.size()) {
     return;
   }
 
   std::string logID = this->getMetadata("logID");
   if (!logID.size()) {
     logID = "1";
   }
 
   bool newLogCreated = SQLiteQueryExecutor::connectionManager.captureLogs(
       backupID, logID, SQLiteQueryExecutor::backupLogDataKey);
   if (!newLogCreated) {
     return;
   }
   this->setMetadata("logID", std::to_string(std::stoi(logID) + 1));
 }
 
 void SQLiteQueryExecutor::setUserDataKeys(
     const std::string &backupDataKey,
     const std::string &backupLogDataKey) const {
   if (SQLiteQueryExecutor::backupDataKey.empty()) {
     throw std::runtime_error("backupDataKey is not set");
   }
 
   if (SQLiteQueryExecutor::backupLogDataKey.empty()) {
     throw std::runtime_error("invalid backupLogDataKey size");
   }
 
   if (backupDataKey.size() != SQLiteQueryExecutor::backupDataKeySize) {
     throw std::runtime_error("invalid backupDataKey size");
   }
 
   if (backupLogDataKey.size() != SQLiteQueryExecutor::backupLogDataKeySize) {
     throw std::runtime_error("invalid backupLogDataKey size");
   }
 
   std::string rekey_encryption_key_query =
       "PRAGMA rekey = \"x'" + backupDataKey + "'\";";
 
   executeQuery(
       SQLiteQueryExecutor::getConnection(), rekey_encryption_key_query);
 
   CommSecureStore::set(CommSecureStore::backupDataKey, backupDataKey);
   SQLiteQueryExecutor::backupDataKey = backupDataKey;
 
   CommSecureStore::set(CommSecureStore::backupLogDataKey, backupLogDataKey);
   SQLiteQueryExecutor::backupLogDataKey = backupLogDataKey;
 }
 #endif
 
 void SQLiteQueryExecutor::restoreFromMainCompaction(
     std::string mainCompactionPath,
     std::string mainCompactionEncryptionKey,
     std::string maxVersion) const {
 
   if (!file_exists(mainCompactionPath)) {
     throw std::runtime_error("Restore attempt but backup file does not exist.");
   }
 
   sqlite3 *backupDB;
   if (!is_database_queryable(
           backupDB, true, mainCompactionPath, mainCompactionEncryptionKey)) {
     throw std::runtime_error("Backup file or encryption key corrupted.");
   }
 
 // We don't want to run `PRAGMA key = ...;`
 // on main web database. The context is here:
 // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web
 #ifdef EMSCRIPTEN
   std::string plaintextBackupPath = mainCompactionPath + "_plaintext";
   if (file_exists(plaintextBackupPath)) {
     attempt_delete_file(
         plaintextBackupPath,
         "Failed to delete plaintext backup file from previous backup "
         "attempt.");
   }
 
   std::string plaintextMigrationDBQuery = "PRAGMA key = \"x'" +
       mainCompactionEncryptionKey +
       "'\";"
       "ATTACH DATABASE '" +
       plaintextBackupPath +
       "' AS plaintext KEY '';"
       "SELECT sqlcipher_export('plaintext');"
       "DETACH DATABASE plaintext;";
 
   sqlite3_open(mainCompactionPath.c_str(), &backupDB);
 
   char *plaintextMigrationErr;
   sqlite3_exec(
       backupDB,
       plaintextMigrationDBQuery.c_str(),
       nullptr,
       nullptr,
       &plaintextMigrationErr);
   sqlite3_close(backupDB);
 
   if (plaintextMigrationErr) {
     std::stringstream error_message;
     error_message << "Failed to migrate backup SQLCipher file to plaintext "
                      "SQLite file. Details"
                   << plaintextMigrationErr << std::endl;
     std::string error_message_str = error_message.str();
     sqlite3_free(plaintextMigrationErr);
 
     throw std::runtime_error(error_message_str);
   }
 
   sqlite3_open(plaintextBackupPath.c_str(), &backupDB);
 #else
   sqlite3_open(mainCompactionPath.c_str(), &backupDB);
   set_encryption_key(backupDB, mainCompactionEncryptionKey);
 #endif
 
   int version = this->getSyncedDatabaseVersion(backupDB).value_or(-1);
   if (version > std::stoi(maxVersion)) {
     std::stringstream error_message;
     error_message << "Failed to restore a backup because it was created "
                   << "with version " << version
                   << " that is newer than the max supported version "
                   << maxVersion << std::endl;
     sqlite3_close(backupDB);
     throw std::runtime_error(error_message.str());
   }
 
   sqlite3_backup *backupObj = sqlite3_backup_init(
       SQLiteQueryExecutor::getConnection(), "main", backupDB, "main");
   if (!backupObj) {
     std::stringstream error_message;
     error_message << "Failed to init backup for main compaction. Details: "
                   << sqlite3_errmsg(SQLiteQueryExecutor::getConnection())
                   << std::endl;
     sqlite3_close(backupDB);
     throw std::runtime_error(error_message.str());
   }
 
   int backupResult = sqlite3_backup_step(backupObj, -1);
   sqlite3_backup_finish(backupObj);
   sqlite3_close(backupDB);
   if (backupResult == SQLITE_BUSY || backupResult == SQLITE_LOCKED) {
     throw std::runtime_error(
         "Programmer error. Database in transaction during restore attempt.");
   } else if (backupResult != SQLITE_DONE) {
     std::stringstream error_message;
     error_message << "Failed to restore database from backup. Details: "
                   << sqlite3_errstr(backupResult);
     throw std::runtime_error(error_message.str());
   }
 
 #ifdef EMSCRIPTEN
   attempt_delete_file(
       plaintextBackupPath,
       "Failed to delete plaintext compaction file after successful restore.");
 #endif
 
   attempt_delete_file(
       mainCompactionPath,
       "Failed to delete main compaction file after successful restore.");
 }
 
 void SQLiteQueryExecutor::restoreFromBackupLog(
     const std::vector<std::uint8_t> &backupLog) const {
   SQLiteQueryExecutor::connectionManager.restoreFromBackupLog(backupLog);
 }
 
 } // namespace comm
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
index 6735d23af..e3d529d25 100644
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
@@ -1,234 +1,241 @@
 #pragma once
 
 #include "../CryptoTools/Persist.h"
 #include "DatabaseQueryExecutor.h"
 #include "NativeSQLiteConnectionManager.h"
 #include "entities/AuxUserInfo.h"
 #include "entities/CommunityInfo.h"
+#include "entities/DMOperation.h"
 #include "entities/Draft.h"
 #include "entities/IntegrityThreadHash.h"
 #include "entities/KeyserverInfo.h"
 #include "entities/LocalMessageInfo.h"
 #include "entities/Media.h"
 #include "entities/Message.h"
 #include "entities/MessageSearchResult.h"
 #include "entities/SQLiteStatementWrapper.h"
 #include "entities/ThreadActivityEntry.h"
 #include "entities/UserInfo.h"
 
 #include <mutex>
 #include <string>
 #include <unordered_set>
 
 namespace comm {
 
 class SQLiteQueryExecutor : public DatabaseQueryExecutor {
   static void migrate();
   static sqlite3 *getConnection();
   static void closeConnection();
 
   static std::once_flag initialized;
   static int backupDataKeySize;
   static std::string backupLogDataKey;
   static int backupLogDataKeySize;
 
 #ifndef EMSCRIPTEN
   static NativeSQLiteConnectionManager connectionManager;
   static std::unordered_set<std::string> backedUpTablesBlocklist;
   static void generateBackupDataKey();
   static void generateBackupLogDataKey();
   static void initializeTablesForLogMonitoring();
 #else
   static SQLiteConnectionManager connectionManager;
   std::vector<MessageWithMedias>
   transformToWebMessages(const std::vector<MessageEntity> &messages) const;
 #endif
 
   std::optional<int> getSyncedDatabaseVersion(sqlite3 *db) const;
   std::vector<MessageEntity>
   processMessagesResults(SQLiteStatementWrapper &preparedSQL) const;
   std::string getThickThreadTypesList() const;
 
 public:
   static std::string sqliteFilePath;
   static std::string backupDataKey;
 
   SQLiteQueryExecutor();
   ~SQLiteQueryExecutor();
   SQLiteQueryExecutor(std::string sqliteFilePath);
   std::unique_ptr<Thread> getThread(std::string threadID) const override;
   std::string getDraft(std::string key) const override;
   void updateDraft(std::string key, std::string text) const override;
   bool moveDraft(std::string oldKey, std::string newKey) const override;
   std::vector<Draft> getAllDrafts() const override;
   void removeAllDrafts() const override;
   void removeDrafts(const std::vector<std::string> &ids) const override;
   void removeAllMessages() const override;
   std::vector<MessageEntity> getInitialMessages() const override;
   std::vector<MessageEntity>
   fetchMessages(std::string threadID, int limit, int offset) const override;
   void removeMessages(const std::vector<std::string> &ids) const override;
   void removeMessagesForThreads(
       const std::vector<std::string> &threadIDs) const override;
   void replaceMessage(const Message &message) const override;
   void rekeyMessage(std::string from, std::string to) const override;
   void replaceMessageStoreThreads(
       const std::vector<MessageStoreThread> &threads) const override;
   void
   removeMessageStoreThreads(const std::vector<std::string> &ids) const override;
   void removeAllMessageStoreThreads() const override;
   std::vector<MessageStoreThread> getAllMessageStoreThreads() const override;
   void removeAllMedia() const override;
   void
   removeMediaForMessages(const std::vector<std::string> &msgIDs) const override;
   void removeMediaForMessage(std::string msgID) const override;
   void removeMediaForThreads(
       const std::vector<std::string> &threadIDs) const override;
   void replaceMedia(const Media &media) const override;
   void rekeyMediaContainers(std::string from, std::string to) const override;
   std::vector<Thread> getAllThreads() const override;
   void removeThreads(std::vector<std::string> ids) const override;
   void replaceThread(const Thread &thread) const override;
   void removeAllThreads() const override;
   void replaceReport(const Report &report) const override;
   void removeReports(const std::vector<std::string> &ids) const override;
   void removeAllReports() const override;
   std::vector<Report> getAllReports() const override;
   void setPersistStorageItem(std::string key, std::string item) const override;
   void removePersistStorageItem(std::string key) const override;
   std::string getPersistStorageItem(std::string key) const override;
   void replaceUser(const UserInfo &userInfo) const override;
   void removeUsers(const std::vector<std::string> &ids) const override;
   void removeAllUsers() const override;
   std::vector<UserInfo> getAllUsers() const override;
   void replaceKeyserver(const KeyserverInfo &keyserverInfo) const override;
   void removeKeyservers(const std::vector<std::string> &ids) const override;
   void removeAllKeyservers() const override;
   std::vector<KeyserverInfo> getAllKeyservers() const override;
   void replaceCommunity(const CommunityInfo &communityInfo) const override;
   void removeCommunities(const std::vector<std::string> &ids) const override;
   void removeAllCommunities() const override;
   std::vector<CommunityInfo> getAllCommunities() const override;
   void replaceIntegrityThreadHashes(
       const std::vector<IntegrityThreadHash> &threadHashes) const override;
   void removeIntegrityThreadHashes(
       const std::vector<std::string> &ids) const override;
   void removeAllIntegrityThreadHashes() const override;
   std::vector<IntegrityThreadHash> getAllIntegrityThreadHashes() const override;
   void replaceSyncedMetadataEntry(
       const SyncedMetadataEntry &syncedMetadataEntry) const override;
   void
   removeSyncedMetadata(const std::vector<std::string> &names) const override;
   void removeAllSyncedMetadata() const override;
   std::vector<SyncedMetadataEntry> getAllSyncedMetadata() const override;
   void replaceAuxUserInfo(const AuxUserInfo &userInfo) const override;
   void removeAuxUserInfos(const std::vector<std::string> &ids) const override;
   void removeAllAuxUserInfos() const override;
   virtual std::vector<AuxUserInfo> getAllAuxUserInfos() const override;
   void replaceThreadActivityEntry(
       const ThreadActivityEntry &threadActivityEntry) const override;
   void removeThreadActivityEntries(
       const std::vector<std::string> &ids) const override;
   void removeAllThreadActivityEntries() const override;
   std::vector<ThreadActivityEntry> getAllThreadActivityEntries() const override;
   void replaceEntry(const EntryInfo &entryInfo) const override;
   void removeEntries(const std::vector<std::string> &ids) const override;
   void removeAllEntries() const override;
   std::vector<EntryInfo> getAllEntries() const override;
   void replaceMessageStoreLocalMessageInfo(
       const LocalMessageInfo &localMessageInfo) const override;
   void removeMessageStoreLocalMessageInfos(
       const std::vector<std::string> &ids) const override;
   void removeAllMessageStoreLocalMessageInfos() const override;
   virtual std::vector<LocalMessageInfo>
   getAllMessageStoreLocalMessageInfos() const override;
   void beginTransaction() const override;
   void commitTransaction() const override;
   void rollbackTransaction() const override;
   int getContentAccountID() const override;
   int getNotifsAccountID() const override;
   std::vector<OlmPersistSession> getOlmPersistSessionsData() const override;
   std::optional<std::string>
   getOlmPersistAccountData(int accountID) const override;
   void storeOlmPersistSession(const OlmPersistSession &session) const override;
   void storeOlmPersistAccount(int accountID, const std::string &accountData)
       const override;
   void
   storeOlmPersistData(int accountID, crypto::Persist persist) const override;
   void setNotifyToken(std::string token) const override;
   void clearNotifyToken() const override;
   void stampSQLiteDBUserID(std::string userID) const override;
   std::string getSQLiteStampedUserID() const override;
   void setMetadata(std::string entryName, std::string data) const override;
   void clearMetadata(std::string entryName) const override;
   std::string getMetadata(std::string entryName) const override;
   void restoreFromMainCompaction(
       std::string mainCompactionPath,
       std::string mainCompactionEncryptionKey,
       std::string maxVersion) const override;
   void restoreFromBackupLog(
       const std::vector<std::uint8_t> &backupLog) const override;
   void addOutboundP2PMessages(
       const std::vector<OutboundP2PMessage> &messages) const override;
   std::vector<OutboundP2PMessage> getOutboundP2PMessagesByID(
       const std::vector<std::string> &ids) const override;
   std::vector<OutboundP2PMessage> getUnsentOutboundP2PMessages() const override;
   void removeOutboundP2PMessage(
       std::string confirmedMessageID,
       std::string deviceID) const override;
   void removeAllOutboundP2PMessages(const std::string &deviceID) const override;
   void setCiphertextForOutboundP2PMessage(
       std::string messageID,
       std::string deviceID,
       std::string ciphertext) const override;
   void markOutboundP2PMessageAsSent(std::string messageID, std::string deviceID)
       const override;
   std::vector<std::string>
   resetOutboundP2PMessagesForDevice(std::string deviceID) const override;
   void addInboundP2PMessage(InboundP2PMessage message) const override;
   std::vector<InboundP2PMessage> getAllInboundP2PMessage() const override;
   void
   removeInboundP2PMessages(const std::vector<std::string> &ids) const override;
   std::vector<InboundP2PMessage>
   getInboundP2PMessagesByID(const std::vector<std::string> &ids) const override;
   std::vector<MessageEntity>
   getRelatedMessages(const std::string &messageID) const override;
   void updateMessageSearchIndex(
       std::string originalMessageID,
       std::string messageID,
       std::string processedContent) const override;
   std::vector<MessageEntity> searchMessages(
       std::string query,
       std::string threadID,
       std::optional<std::string> timestampCursor,
       std::optional<std::string> messageIDCursor) const override;
   std::vector<MessageEntity> getRelatedMessagesForSearch(
       const std::vector<std::string> &messageIDs) const override;
+  void replaceDMOperation(const DMOperation &operation) const override;
+  void removeAllDMOperations() const override;
+  void removeDMOperations(const std::vector<std::string> &ids) const override;
+  std::vector<DMOperation> getDMOperations() const override;
+  std::vector<DMOperation>
+  getDMOperationsByType(const std::string &operationType) const override;
 
 #ifdef EMSCRIPTEN
   std::vector<WebThread> getAllThreadsWeb() const override;
   void replaceThreadWeb(const WebThread &thread) const override;
   std::vector<MessageWithMedias> getInitialMessagesWeb() const override;
   std::vector<MessageWithMedias>
   fetchMessagesWeb(std::string threadID, int limit, int offset) const override;
   void replaceMessageWeb(const WebMessage &message) const override;
   NullableString getOlmPersistAccountDataWeb(int accountID) const override;
   std::vector<MessageWithMedias>
   getRelatedMessagesWeb(const std::string &messageID) const override;
   std::vector<MessageWithMedias> searchMessagesWeb(
       std::string query,
       std::string threadID,
       std::optional<std::string> timestampCursor,
       std::optional<std::string> messageIDCursor) const override;
 #else
   static void clearSensitiveData();
   static void initialize(std::string &databasePath);
   void createMainCompaction(std::string backupID) const override;
   void captureBackupLogs() const override;
   void setUserDataKeys(
       const std::string &backupDataKey,
       const std::string &backupLogDataKey) const override;
 #endif
 };
 
 } // namespace comm
diff --git a/native/cpp/CommonCpp/DatabaseManagers/entities/DMOperation.h b/native/cpp/CommonCpp/DatabaseManagers/entities/DMOperation.h
new file mode 100644
index 000000000..524d65dc9
--- /dev/null
+++ b/native/cpp/CommonCpp/DatabaseManagers/entities/DMOperation.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "SQLiteDataConverters.h"
+#include <sqlite3.h>
+#include <string>
+
+namespace comm {
+struct DMOperation {
+
+  std::string id;
+  std::string type;
+  std::string operation;
+
+  static DMOperation fromSQLResult(sqlite3_stmt *sqlRow, int idx) {
+    return DMOperation{
+        getStringFromSQLRow(sqlRow, idx),
+        getStringFromSQLRow(sqlRow, idx + 1),
+        getStringFromSQLRow(sqlRow, idx + 2)};
+  }
+
+  int bindToSQL(sqlite3_stmt *sql, int idx) const {
+    bindStringToSQL(id, sql, idx);
+    bindStringToSQL(type, sql, idx + 1);
+    return bindStringToSQL(operation, sql, idx + 2);
+  }
+};
+
+} // namespace comm
diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj
index 725dcc7d6..35fadf988 100644
--- a/native/ios/Comm.xcodeproj/project.pbxproj
+++ b/native/ios/Comm.xcodeproj/project.pbxproj
@@ -1,1989 +1,1991 @@
 // !$*UTF8*$!
 {
 	archiveVersion = 1;
 	classes = {
 	};
 	objectVersion = 54;
 	objects = {
 
 /* Begin PBXBuildFile section */
 		13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
 		1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */; };
 		34055C152BAD31AC0008E713 /* SyncedMetadataStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */; };
 		34329B442B9EC7EC00233438 /* IntegrityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34329B3F2B9EBFCE00233438 /* IntegrityStore.cpp */; };
 		34BE127D2BC3F78C00CCAD11 /* ThreadActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34BE127C2BC3F78C00CCAD11 /* ThreadActivityStore.cpp */; };
 		34FF25BA2BB757870075EC40 /* AuxUserStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34FF25B92BB757860075EC40 /* AuxUserStore.cpp */; };
 		71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; };
 		711B408425DA97F9005F8F06 /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F26E81B24440D87004049C6 /* dummy.swift */; };
 		71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; };
 		718DE99E2653D41C00365824 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; };
 		71BE844A2636A944002849D2 /* CommCoreModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE843C2636A944002849D2 /* CommCoreModule.cpp */; };
 		71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */; };
 		71BF5B7126B3FF0900EDE27D /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; };
 		71BF5B7526B401D300EDE27D /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7326B401D300EDE27D /* Tools.cpp */; };
 		71BF5B7F26BBDD7400EDE27D /* CryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */; };
 		71CA4A64262DA8E500835C89 /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; };
 		71CA4AEC262F236100835C89 /* Tools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4AEB262F236100835C89 /* Tools.mm */; };
 		71D4D7CC26C50B1000FCDBCD /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; };
 		724995D527B4103A00323FCE /* NotificationService.mm in Sources */ = {isa = PBXBuildFile; fileRef = 724995D427B4103A00323FCE /* NotificationService.mm */; };
 		724995D927B4103A00323FCE /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 724995D127B4103A00323FCE /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
 		724995FB27BA9E8D00323FCE /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 724995FA27BA9E8C00323FCE /* UserNotifications.framework */; };
 		7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */; };
 		7F761E602201141E001B6FB7 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F761E292201141E001B6FB7 /* JavaScriptCore.framework */; };
 		7F788C2C248AA2140098F071 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F788C2B248AA2130098F071 /* SplashScreen.storyboard */; };
 		7F8D602126535E060053CB29 /* OpenSans-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */; };
 		7F8D602226535E060053CB29 /* Anaheim-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */; };
 		7F8D602326535E060053CB29 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */; };
 		7F8D602826535F240053CB29 /* IBMPlexSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */; };
 		7F8D602926535F2A0053CB29 /* IBMPlexSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */; };
 		7FA2DCDE293E62F500991BA4 /* CommIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7FA2DCDC293E62F500991BA4 /* CommIcons.ttf */; };
 		7FA2DCDF293E62F500991BA4 /* SWMansionIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7FA2DCDD293E62F500991BA4 /* SWMansionIcons.ttf */; };
 		7FBB2A7629E94539002C6493 /* utilsJSI-generated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FBB2A7529E94539002C6493 /* utilsJSI-generated.cpp */; };
 		7FBB2A7829E945C2002C6493 /* CommUtilsModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FBB2A7329E944FD002C6493 /* CommUtilsModule.cpp */; };
 		7FBB2A7B29EEA2A4002C6493 /* Base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FBB2A7A29EEA2A4002C6493 /* Base64.cpp */; };
 		7FE4D9F5291DFE9300667BF6 /* commJSI-generated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FE4D9F4291DFE9300667BF6 /* commJSI-generated.cpp */; };
 		816D2D5A2C480E60001C0B67 /* MessageSearchStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 816D2D582C480E60001C0B67 /* MessageSearchStore.cpp */; };
 		8B38121629CE5742000C52E9 /* RustPromiseManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B38121529CE5742000C52E9 /* RustPromiseManager.cpp */; };
 		8B652FA6295EAA5B009F8163 /* RustCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B652FA5295EAA5B009F8163 /* RustCallback.cpp */; };
 		8B99BAAC28D50F3000EB5ADB /* libnative_rust_library.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */; };
 		8B99BAAE28D511FF00EB5ADB /* lib.rs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */; };
 		8BC9568529FC49B00060AE4A /* JSIRust.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8BC9568429FC49B00060AE4A /* JSIRust.cpp */; };
 		8E2CC2592B5C99B0000C94D6 /* KeyserverStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E2CC2582B5C99B0000C94D6 /* KeyserverStore.cpp */; };
 		8E3994552B039A7C00D5E950 /* UserStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E3994532B039A7C00D5E950 /* UserStore.cpp */; };
 		8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */; };
 		8E86A6D329537EBB000BBE7D /* DatabaseManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E86A6D229537EBB000BBE7D /* DatabaseManager.cpp */; };
 		8EA59BD62A6E8E0400EB4F53 /* DraftStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EA59BD42A6E8E0400EB4F53 /* DraftStore.cpp */; };
 		8EA59BD92A73DAB000EB4F53 /* rustJSI-generated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EA59BD72A73DAB000EB4F53 /* rustJSI-generated.cpp */; };
 		8EF775682A74032C0046A385 /* CommRustModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EF775672A74032C0046A385 /* CommRustModule.cpp */; };
 		8EF7756B2A7433630046A385 /* ThreadStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EF775692A7433630046A385 /* ThreadStore.cpp */; };
 		8EF7756E2A7513F40046A385 /* MessageStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EF7756D2A7513F40046A385 /* MessageStore.cpp */; };
 		8EF775712A751B780046A385 /* ReportStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8EF7756F2A751B780046A385 /* ReportStore.cpp */; };
 		B3B02EBF2B8538980020D118 /* CommunityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B02EBD2B8536560020D118 /* CommunityStore.cpp */; };
 		B71AFF1F265EDD8600B22352 /* IBMPlexSans-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */; };
 		CB01F0C22B67EF5A0089E1F9 /* SQLiteDataConverters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB01F0C12B67EF470089E1F9 /* SQLiteDataConverters.cpp */; };
 		CB01F0C42B67F3A10089E1F9 /* SQLiteStatementWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB01F0C32B67F3970089E1F9 /* SQLiteStatementWrapper.cpp */; };
 		CB1648AF27CFBE6A00394D9D /* CryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */; };
 		CB24361829A39A2500FEC4E1 /* NotificationsCryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */; };
 		CB2689002A2DF58000EC7300 /* CommConstants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB2688FF2A2DF56000EC7300 /* CommConstants.cpp */; };
 		CB3220922BDA66B900DB6C5C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CB3220912BDA66B900DB6C5C /* PrivacyInfo.xcprivacy */; };
 		CB3220932BDA66B900DB6C5C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CB3220912BDA66B900DB6C5C /* PrivacyInfo.xcprivacy */; };
 		CB38B48228771C7A00171182 /* NonBlockingLock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47B287718A200171182 /* NonBlockingLock.mm */; };
 		CB38B48328771C8300171182 /* NonBlockingLock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47B287718A200171182 /* NonBlockingLock.mm */; };
 		CB38B48428771CAF00171182 /* EncryptedFileUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47D2877194100171182 /* EncryptedFileUtils.mm */; };
 		CB38B48528771CB800171182 /* EncryptedFileUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47D2877194100171182 /* EncryptedFileUtils.mm */; };
 		CB38B48628771CDD00171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; };
 		CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */; };
 		CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */; };
 		CB3C0A3B2A125C8F009BD4DA /* NotificationsCryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */; };
 		CB3C621127CE4A320054F24C /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; };
 		CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; };
 		CB3CCB012B72470700793640 /* NativeSQLiteConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */; };
 		CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; };
 		CB4821AA27CFB153001AB7E1 /* Tools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4AEB262F236100835C89 /* Tools.mm */; };
 		CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; };
 		CB4821AE27CFB187001AB7E1 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B7326B401D300EDE27D /* Tools.cpp */; };
 		CB4821AF27CFB19D001AB7E1 /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; };
 		CB74AB1C2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB74AB1B2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm */; };
 		CB74AB202B2B0C0A00CBB494 /* RustCSAMetadataEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB74AB1E2B2B0C0900CBB494 /* RustCSAMetadataEmitter.cpp */; };
 		CB7EF17E295C674300B17035 /* CommIOSNotifications.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */; };
 		CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */; };
 		CB90951F29534B32002F2A7F /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; };
 		CB99DB4D2C45327C00B8055E /* NotificationsInboundKeysProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB99DB4C2C45327B00B8055E /* NotificationsInboundKeysProvider.mm */; };
 		CB99DB4E2C45329500B8055E /* NotificationsInboundKeysProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB99DB4C2C45327B00B8055E /* NotificationsInboundKeysProvider.mm */; };
 		CBA5F8852B6979F7005BE700 /* SQLiteConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */; };
 		CBAAA4702B459181007599DA /* BackupOperationsExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBAAA46E2B459181007599DA /* BackupOperationsExecutor.cpp */; };
 		CBAB638A2BFCCA9B003B089F /* EntryStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBAB63882BFCB087003B089F /* EntryStore.cpp */; };
 		CBB0DF602B768007008E22FF /* CommMMKV.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBB0DF5F2B768007008E22FF /* CommMMKV.mm */; };
 		CBB0DF612B768007008E22FF /* CommMMKV.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBB0DF5F2B768007008E22FF /* CommMMKV.mm */; };
 		CBCA09062A8E0E7400F75B3E /* StaffUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */; };
 		CBCA09072A8E0E7D00F75B3E /* StaffUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */; };
 		CBCF984F2BA499DA00DBC3D9 /* CommIOSServicesClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBCF984D2BA499DA00DBC3D9 /* CommIOSServicesClient.mm */; };
 		CBCF98502BA49A0500DBC3D9 /* CommIOSServicesClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBCF984D2BA499DA00DBC3D9 /* CommIOSServicesClient.mm */; };
 		CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */; };
 		CBFBEEBA2B4ED90600729F1D /* RustBackupExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBFBEEB82B4ED90600729F1D /* RustBackupExecutor.cpp */; };
 		CBFE58292885852B003B94C9 /* ThreadOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBFE58282885852B003B94C9 /* ThreadOperations.cpp */; };
 		D7DB6E0F85B2DBE15B01EC21 /* libPods-Comm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */; };
 		DFD5E77C2B05181400C32B6A /* RustSecureStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFD5E77B2B05181400C32B6A /* RustSecureStore.cpp */; };
 		DFD5E77E2B05264000C32B6A /* AESCrypto.mm in Sources */ = {isa = PBXBuildFile; fileRef = DFD5E77D2B05264000C32B6A /* AESCrypto.mm */; };
 		DFD5E7862B052B1400C32B6A /* RustAESCrypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFD5E7842B052B1400C32B6A /* RustAESCrypto.cpp */; };
 		F02C296C528B51ADAB5AA19D /* libPods-NotificationService.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
 		713EE40B26C6676B003D7C48 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
 			proxyType = 1;
 			remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
 			remoteInfo = Comm;
 		};
 		724995D727B4103A00323FCE /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
 			proxyType = 1;
 			remoteGlobalIDString = 724995D027B4103A00323FCE;
 			remoteInfo = NotificationService;
 		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
 		724995DA27B4103A00323FCE /* Embed App Extensions */ = {
 			isa = PBXCopyFilesBuildPhase;
 			buildActionMask = 2147483647;
 			dstPath = "";
 			dstSubfolderSpec = 13;
 			files = (
 				724995D927B4103A00323FCE /* NotificationService.appex in Embed App Extensions */,
 			);
 			name = "Embed App Extensions";
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		0E02676D2D81EAD800788249 /* DMOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DMOperation.h; sourceTree = "<group>"; };
 		13B07F961A680F5B00A75B9A /* Comm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Comm.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Comm/AppDelegate.h; sourceTree = "<group>"; };
 		13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = Comm/AppDelegate.mm; sourceTree = "<group>"; };
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Comm/Images.xcassets; sourceTree = "<group>"; };
 		13B07FB61A68108700A75B9A /* Info.release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.release.plist; path = Comm/Info.release.plist; sourceTree = "<group>"; };
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Comm/main.m; sourceTree = "<group>"; };
 		2DDA0A22FECC9DAA5C19C35D /* Metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metadata.h; sourceTree = "<group>"; };
 		34055C132BAD31AB0008E713 /* SyncedMetadataStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SyncedMetadataStore.h; path = PersistentStorageUtilities/DataStores/SyncedMetadataStore.h; sourceTree = "<group>"; };
 		34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SyncedMetadataStore.cpp; path = PersistentStorageUtilities/DataStores/SyncedMetadataStore.cpp; sourceTree = "<group>"; };
 		34055C162BAD31BD0008E713 /* SyncedMetadataStoreOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyncedMetadataStoreOperations.h; sourceTree = "<group>"; };
 		34329B3E2B9EBD3400233438 /* IntegrityStoreOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegrityStoreOperations.h; sourceTree = "<group>"; };
 		34329B3F2B9EBFCE00233438 /* IntegrityStore.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IntegrityStore.cpp; path = PersistentStorageUtilities/DataStores/IntegrityStore.cpp; sourceTree = "<group>"; };
 		34329B402B9EBFCE00233438 /* IntegrityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IntegrityStore.h; path = PersistentStorageUtilities/DataStores/IntegrityStore.h; sourceTree = "<group>"; };
 		34329B452B9EC96200233438 /* IntegrityThreadHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegrityThreadHash.h; sourceTree = "<group>"; };
 		34BE12762BC3F3D100CCAD11 /* ThreadActivityStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadActivityStoreOperations.h; sourceTree = "<group>"; };
 		34BE127B2BC3F78B00CCAD11 /* ThreadActivityStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadActivityStore.h; path = PersistentStorageUtilities/DataStores/ThreadActivityStore.h; sourceTree = "<group>"; };
 		34BE127C2BC3F78C00CCAD11 /* ThreadActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadActivityStore.cpp; path = PersistentStorageUtilities/DataStores/ThreadActivityStore.cpp; sourceTree = "<group>"; };
 		34FF25A62BB738DC0075EC40 /* AuxUserStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AuxUserStoreOperations.h; sourceTree = "<group>"; };
 		34FF25B82BB753B30075EC40 /* AuxUserStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AuxUserStore.h; path = PersistentStorageUtilities/DataStores/AuxUserStore.h; sourceTree = "<group>"; };
 		34FF25B92BB757860075EC40 /* AuxUserStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AuxUserStore.cpp; path = PersistentStorageUtilities/DataStores/AuxUserStore.cpp; sourceTree = "<group>"; };
 		3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationService.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Comm/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
 		71142A7526C2650A0039DCBD /* CommSecureStoreIOSWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommSecureStoreIOSWrapper.h; path = Comm/CommSecureStoreIOSWrapper.h; sourceTree = "<group>"; };
 		71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommSecureStoreIOSWrapper.mm; path = Comm/CommSecureStoreIOSWrapper.mm; sourceTree = "<group>"; };
 		711CF80E25DC096000A00FBD /* libFolly.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libFolly.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		713EE40626C6676B003D7C48 /* CommTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		713EE40A26C6676B003D7C48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformSpecificTools.mm; path = Comm/PlatformSpecificTools.mm; sourceTree = "<group>"; };
 		718DE99C2653D41C00365824 /* WorkerThread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerThread.cpp; sourceTree = "<group>"; };
 		718DE99D2653D41C00365824 /* WorkerThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WorkerThread.h; sourceTree = "<group>"; };
 		71B8CCBD26BD4DEB0040C0A2 /* CommSecureStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommSecureStore.h; sourceTree = "<group>"; };
 		71BE84392636A944002849D2 /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = "<group>"; };
 		71BE843C2636A944002849D2 /* CommCoreModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommCoreModule.cpp; sourceTree = "<group>"; };
 		71BE843E2636A944002849D2 /* CommCoreModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommCoreModule.h; sourceTree = "<group>"; };
 		71BE84402636A944002849D2 /* DatabaseQueryExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseQueryExecutor.h; sourceTree = "<group>"; };
 		71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteQueryExecutor.cpp; sourceTree = "<group>"; };
 		71BE84422636A944002849D2 /* SQLiteQueryExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQLiteQueryExecutor.h; sourceTree = "<group>"; };
 		71BE84432636A944002849D2 /* DatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseManager.h; sourceTree = "<group>"; };
 		71BE84452636A944002849D2 /* Draft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Draft.h; sourceTree = "<group>"; };
 		71BF5B6F26B3FF0900EDE27D /* Session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Session.cpp; sourceTree = "<group>"; };
 		71BF5B7026B3FF0900EDE27D /* Session.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Session.h; sourceTree = "<group>"; };
 		71BF5B7226B3FFBC00EDE27D /* Persist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Persist.h; sourceTree = "<group>"; };
 		71BF5B7326B401D300EDE27D /* Tools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Tools.cpp; sourceTree = "<group>"; };
 		71BF5B7426B401D300EDE27D /* Tools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Tools.h; sourceTree = "<group>"; };
 		71BF5B7A26BBDA6000EDE27D /* CryptoModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoModule.h; sourceTree = "<group>"; };
 		71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoModule.cpp; sourceTree = "<group>"; };
 		71CA4A63262DA8E500835C89 /* Logger.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Logger.mm; path = Comm/Logger.mm; sourceTree = "<group>"; };
 		71CA4AEA262F230A00835C89 /* Tools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = Comm/Tools.h; sourceTree = "<group>"; };
 		71CA4AEB262F236100835C89 /* Tools.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = Tools.mm; path = Comm/Tools.mm; sourceTree = "<group>"; };
 		71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommSecureStore.mm; path = Comm/CommSecureStore.mm; sourceTree = "<group>"; };
 		71DC160C270C43D300822863 /* PlatformSpecificTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformSpecificTools.h; sourceTree = "<group>"; };
 		724995D127B4103A00323FCE /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
 		724995D327B4103A00323FCE /* NotificationService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationService.h; sourceTree = "<group>"; };
 		724995D427B4103A00323FCE /* NotificationService.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NotificationService.mm; sourceTree = "<group>"; };
 		724995D627B4103A00323FCE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		724995FA27BA9E8C00323FCE /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
 		75291F0228F9A09E00F4C80E /* DeviceID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceID.h; sourceTree = "<group>"; };
 		75291F0328F9A0AE00F4C80E /* DeviceID.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceID.cpp; sourceTree = "<group>"; };
 		769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NotificationService/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
 		7F26E81B24440D87004049C6 /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dummy.swift; sourceTree = "<group>"; };
 		7F446E2229C3AF3800670288 /* ReactionMessageSpec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ReactionMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/ReactionMessageSpec.h; sourceTree = "<group>"; };
 		7F446E2329C3B2BE00670288 /* SidebarSourceMessageSpec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SidebarSourceMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/SidebarSourceMessageSpec.h; sourceTree = "<group>"; };
 		7F554F822332D58B007CB9F7 /* Info.debug.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.debug.plist; path = Comm/Info.debug.plist; sourceTree = "<group>"; };
 		7F761E292201141E001B6FB7 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
 		7F788C2B248AA2130098F071 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SplashScreen.storyboard; sourceTree = "<group>"; };
 		7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Semibold.ttf"; path = "Resources/OpenSans-Semibold.ttf"; sourceTree = "<group>"; };
 		7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Anaheim-Regular.ttf"; path = "Resources/Anaheim-Regular.ttf"; sourceTree = "<group>"; };
 		7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Regular.ttf"; path = "Resources/OpenSans-Regular.ttf"; sourceTree = "<group>"; };
 		7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Regular.ttf"; path = "Resources/IBMPlexSans-Regular.ttf"; sourceTree = "<group>"; };
 		7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Bold.ttf"; path = "Resources/IBMPlexSans-Bold.ttf"; sourceTree = "<group>"; };
 		7FA2DCDC293E62F500991BA4 /* CommIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = CommIcons.ttf; path = ../fonts/CommIcons.ttf; sourceTree = "<group>"; };
 		7FA2DCDD293E62F500991BA4 /* SWMansionIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = SWMansionIcons.ttf; path = ../fonts/SWMansionIcons.ttf; sourceTree = "<group>"; };
 		7FBB2A7329E944FD002C6493 /* CommUtilsModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CommUtilsModule.cpp; sourceTree = "<group>"; };
 		7FBB2A7429E9450E002C6493 /* CommUtilsModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommUtilsModule.h; sourceTree = "<group>"; };
 		7FBB2A7529E94539002C6493 /* utilsJSI-generated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "utilsJSI-generated.cpp"; sourceTree = "<group>"; };
 		7FBB2A7729E94541002C6493 /* utilsJSI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utilsJSI.h; sourceTree = "<group>"; };
 		7FBB2A7929EA752D002C6493 /* Base64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Base64.h; sourceTree = "<group>"; };
 		7FBB2A7A29EEA2A4002C6493 /* Base64.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Base64.cpp; sourceTree = "<group>"; };
 		7FCEA2DC2444010B004017B1 /* Comm-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Comm-Bridging-Header.h"; sourceTree = "<group>"; };
 		7FCFD8BD1E81B8DF00629B0E /* Comm.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Comm.entitlements; path = Comm/Comm.entitlements; sourceTree = "<group>"; };
 		7FE4D9F3291DFE9300667BF6 /* commJSI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commJSI.h; sourceTree = "<group>"; };
 		7FE4D9F4291DFE9300667BF6 /* commJSI-generated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "commJSI-generated.cpp"; sourceTree = "<group>"; };
 		816D2D582C480E60001C0B67 /* MessageSearchStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageSearchStore.cpp; path = PersistentStorageUtilities/DataStores/MessageSearchStore.cpp; sourceTree = "<group>"; };
 		816D2D592C480E60001C0B67 /* MessageSearchStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageSearchStore.h; path = PersistentStorageUtilities/DataStores/MessageSearchStore.h; sourceTree = "<group>"; };
 		816D2D5B2C480E9E001C0B67 /* MessageSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageSearchResult.h; sourceTree = "<group>"; };
 		891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
 		8B38121529CE5742000C52E9 /* RustPromiseManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustPromiseManager.cpp; sourceTree = "<group>"; };
 		8B652FA1295EA6B8009F8163 /* RustPromiseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustPromiseManager.h; sourceTree = "<group>"; };
 		8B652FA4295EA9F1009F8163 /* RustCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustCallback.h; sourceTree = "<group>"; };
 		8B652FA5295EAA5B009F8163 /* RustCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RustCallback.cpp; sourceTree = "<group>"; };
 		8B99AF6D28D50D4800EB5ADB /* lib.rs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lib.rs.h; sourceTree = "<group>"; };
 		8B99B59928D50D4900EB5ADB /* cxx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cxx.h; sourceTree = "<group>"; };
 		8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libnative_rust_library.a; path = ../native_rust_library/target/universal/release/libnative_rust_library.a; sourceTree = "<group>"; };
 		8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lib.rs.cc; sourceTree = "<group>"; };
 		8BC9568329FC49920060AE4A /* JSIRust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIRust.h; sourceTree = "<group>"; };
 		8BC9568429FC49B00060AE4A /* JSIRust.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIRust.cpp; sourceTree = "<group>"; };
 		8E2CC2562B5C999A000C94D6 /* KeyserverStoreOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyserverStoreOperations.h; sourceTree = "<group>"; };
 		8E2CC2572B5C99B0000C94D6 /* KeyserverStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KeyserverStore.h; path = PersistentStorageUtilities/DataStores/KeyserverStore.h; sourceTree = "<group>"; };
 		8E2CC2582B5C99B0000C94D6 /* KeyserverStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KeyserverStore.cpp; path = PersistentStorageUtilities/DataStores/KeyserverStore.cpp; sourceTree = "<group>"; };
 		8E3994532B039A7C00D5E950 /* UserStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserStore.cpp; path = PersistentStorageUtilities/DataStores/UserStore.cpp; sourceTree = "<group>"; };
 		8E3994542B039A7C00D5E950 /* UserStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserStore.h; path = PersistentStorageUtilities/DataStores/UserStore.h; sourceTree = "<group>"; };
 		8E3994562B039A9300D5E950 /* UserStoreOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserStoreOperations.h; sourceTree = "<group>"; };
 		8E43C32B291E5B4A009378F5 /* TerminateApp.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TerminateApp.mm; path = Comm/TerminateApp.mm; sourceTree = "<group>"; };
 		8E43C32E291E5B9D009378F5 /* TerminateApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TerminateApp.h; path = ../cpp/CommonCpp/Tools/TerminateApp.h; sourceTree = "<group>"; };
 		8E86A6D229537EBB000BBE7D /* DatabaseManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseManager.cpp; sourceTree = "<group>"; };
 		8EA59BD22A6E800100EB4F53 /* NativeModuleUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeModuleUtils.h; sourceTree = "<group>"; };
 		8EA59BD32A6E8CB700EB4F53 /* BaseDataStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BaseDataStore.h; path = PersistentStorageUtilities/DataStores/BaseDataStore.h; sourceTree = "<group>"; };
 		8EA59BD42A6E8E0400EB4F53 /* DraftStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DraftStore.cpp; path = PersistentStorageUtilities/DataStores/DraftStore.cpp; sourceTree = "<group>"; };
 		8EA59BD52A6E8E0400EB4F53 /* DraftStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DraftStore.h; path = PersistentStorageUtilities/DataStores/DraftStore.h; sourceTree = "<group>"; };
 		8EA59BD72A73DAB000EB4F53 /* rustJSI-generated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "rustJSI-generated.cpp"; sourceTree = "<group>"; };
 		8EA59BD82A73DAB000EB4F53 /* rustJSI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rustJSI.h; sourceTree = "<group>"; };
 		8EE6E49F2A39CCAB00AE6BCD /* ReportStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReportStoreOperations.h; sourceTree = "<group>"; };
 		8EE6E4A02A39CCAB00AE6BCD /* DraftStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DraftStoreOperations.h; sourceTree = "<group>"; };
 		8EF775662A74032C0046A385 /* CommRustModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommRustModule.h; sourceTree = "<group>"; };
 		8EF775672A74032C0046A385 /* CommRustModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommRustModule.cpp; sourceTree = "<group>"; };
 		8EF775692A7433630046A385 /* ThreadStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadStore.cpp; path = PersistentStorageUtilities/DataStores/ThreadStore.cpp; sourceTree = "<group>"; };
 		8EF7756A2A7433630046A385 /* ThreadStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadStore.h; path = PersistentStorageUtilities/DataStores/ThreadStore.h; sourceTree = "<group>"; };
 		8EF7756C2A7513F40046A385 /* MessageStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageStore.h; path = PersistentStorageUtilities/DataStores/MessageStore.h; sourceTree = "<group>"; };
 		8EF7756D2A7513F40046A385 /* MessageStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageStore.cpp; path = PersistentStorageUtilities/DataStores/MessageStore.cpp; sourceTree = "<group>"; };
 		8EF7756F2A751B780046A385 /* ReportStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ReportStore.cpp; path = PersistentStorageUtilities/DataStores/ReportStore.cpp; sourceTree = "<group>"; };
 		8EF775702A751B780046A385 /* ReportStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ReportStore.h; path = PersistentStorageUtilities/DataStores/ReportStore.h; sourceTree = "<group>"; };
 		913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; };
 		994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Comm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		B3B02EBC2B8534C00020D118 /* CommunityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommunityStore.h; path = PersistentStorageUtilities/DataStores/CommunityStore.h; sourceTree = "<group>"; };
 		B3B02EBD2B8536560020D118 /* CommunityStore.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CommunityStore.cpp; path = PersistentStorageUtilities/DataStores/CommunityStore.cpp; sourceTree = "<group>"; };
 		B3B02EBE2B8538860020D118 /* CommunityStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommunityStoreOperations.h; sourceTree = "<group>"; };
 		B7055C6B26E477CF00BE0548 /* MessageStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageStoreOperations.h; sourceTree = "<group>"; };
 		B70FBC1226B047050040F480 /* Message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Message.h; sourceTree = "<group>"; };
 		B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "IBMPlexSans-Medium.ttf"; path = "Resources/IBMPlexSans-Medium.ttf"; sourceTree = "<group>"; };
 		B7906F692720905A009BBBF5 /* ThreadStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadStoreOperations.h; sourceTree = "<group>"; };
 		B7906F6A27209091009BBBF5 /* OlmPersistAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OlmPersistAccount.h; sourceTree = "<group>"; };
 		B7906F6B27209091009BBBF5 /* OlmPersistSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OlmPersistSession.h; sourceTree = "<group>"; };
 		B7906F6C27209091009BBBF5 /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Thread.h; sourceTree = "<group>"; };
 		B7E937CA26F448E700022A7C /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
 		C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Comm.release.xcconfig"; path = "Target Support Files/Pods-Comm/Pods-Comm.release.xcconfig"; sourceTree = "<group>"; };
 		CB01F0BF2B67CDC20089E1F9 /* SQLiteStatementWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteStatementWrapper.h; sourceTree = "<group>"; };
 		CB01F0C02B67CDC20089E1F9 /* SQLiteDataConverters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteDataConverters.h; sourceTree = "<group>"; };
 		CB01F0C12B67EF470089E1F9 /* SQLiteDataConverters.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteDataConverters.cpp; sourceTree = "<group>"; };
 		CB01F0C32B67F3970089E1F9 /* SQLiteStatementWrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteStatementWrapper.cpp; sourceTree = "<group>"; };
 		CB24361629A397AB00FEC4E1 /* NotificationsCryptoModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotificationsCryptoModule.h; path = Notifications/BackgroundDataStorage/NotificationsCryptoModule.h; sourceTree = "<group>"; };
 		CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotificationsCryptoModule.cpp; path = Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp; sourceTree = "<group>"; };
 		CB2688FE2A2DF55F00EC7300 /* CommConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommConstants.h; sourceTree = "<group>"; };
 		CB2688FF2A2DF56000EC7300 /* CommConstants.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CommConstants.cpp; sourceTree = "<group>"; };
 		CB30C12327D0ACF700FBE8DE /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = "<group>"; };
 		CB3220912BDA66B900DB6C5C /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
 		CB38B4792877179A00171182 /* NonBlockingLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NonBlockingLock.h; path = Comm/TemporaryMessageStorage/NonBlockingLock.h; sourceTree = "<group>"; };
 		CB38B47B287718A200171182 /* NonBlockingLock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = NonBlockingLock.mm; path = Comm/TemporaryMessageStorage/NonBlockingLock.mm; sourceTree = "<group>"; };
 		CB38B47C2877190100171182 /* EncryptedFileUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EncryptedFileUtils.h; path = Comm/TemporaryMessageStorage/EncryptedFileUtils.h; sourceTree = "<group>"; };
 		CB38B47D2877194100171182 /* EncryptedFileUtils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = EncryptedFileUtils.mm; path = Comm/TemporaryMessageStorage/EncryptedFileUtils.mm; sourceTree = "<group>"; };
 		CB38B47E287719C500171182 /* TemporaryMessageStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TemporaryMessageStorage.h; path = Comm/TemporaryMessageStorage/TemporaryMessageStorage.h; sourceTree = "<group>"; };
 		CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = TemporaryMessageStorage.mm; path = Comm/TemporaryMessageStorage/TemporaryMessageStorage.mm; sourceTree = "<group>"; };
 		CB38F2AE286C6C870010535C /* MessageSpecs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageSpecs.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs.h; sourceTree = "<group>"; };
 		CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageOperationsUtilities.cpp; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageOperationsUtilities.cpp; sourceTree = "<group>"; };
 		CB38F2B0286C6C870010535C /* MessageOperationsUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageOperationsUtilities.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageOperationsUtilities.h; sourceTree = "<group>"; };
 		CB38F2B2286C6C970010535C /* CreateThreadMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateThreadMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateThreadMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B3286C6C970010535C /* TextMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/TextMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B4286C6C970010535C /* CreateSidebarMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateSidebarMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateSidebarMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B5286C6C970010535C /* ChangeRoleMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChangeRoleMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/ChangeRoleMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B6286C6C970010535C /* RestoreEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RestoreEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/RestoreEntryMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B7286C6C970010535C /* MessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/MessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B8286C6C970010535C /* ChangeSettingsMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ChangeSettingsMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/ChangeSettingsMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2B9286C6C970010535C /* UnsupportedMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnsupportedMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/UnsupportedMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BA286C6C970010535C /* CreateEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateEntryMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BB286C6C970010535C /* EditEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EditEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/EditEntryMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BC286C6C970010535C /* CreateSubThreadMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CreateSubThreadMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/CreateSubThreadMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BD286C6C970010535C /* MultimediaMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MultimediaMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/MultimediaMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BE286C6C980010535C /* DeleteEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeleteEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/DeleteEntryMessageSpec.h; sourceTree = "<group>"; };
 		CB38F2BF286C6C980010535C /* UpdateRelationshipMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateRelationshipMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/UpdateRelationshipMessageSpec.h; sourceTree = "<group>"; };
 		CB3C621327CE66540054F24C /* libEXSecureStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libEXSecureStore.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		CB3CCAFF2B7246F400793640 /* NativeSQLiteConnectionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeSQLiteConnectionManager.h; sourceTree = "<group>"; };
 		CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeSQLiteConnectionManager.cpp; sourceTree = "<group>"; };
 		CB74AB1B2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommServicesAuthMetadataEmitter.mm; path = Comm/CommServicesAuthMetadataEmitter.mm; sourceTree = "<group>"; };
 		CB74AB1E2B2B0C0900CBB494 /* RustCSAMetadataEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustCSAMetadataEmitter.cpp; sourceTree = "<group>"; };
 		CB74AB1F2B2B0C0900CBB494 /* RustCSAMetadataEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustCSAMetadataEmitter.h; sourceTree = "<group>"; };
 		CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSNotificationsBridgeQueue.mm; path = Comm/CommIOSNotifications/CommIOSNotificationsBridgeQueue.mm; sourceTree = "<group>"; };
 		CB7EF17C295C580500B17035 /* CommIOSNotificationsBridgeQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommIOSNotificationsBridgeQueue.h; path = Comm/CommIOSNotifications/CommIOSNotificationsBridgeQueue.h; sourceTree = "<group>"; };
 		CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSNotifications.mm; path = Comm/CommIOSNotifications/CommIOSNotifications.mm; sourceTree = "<group>"; };
 		CB90951929531663002F2A7F /* CommIOSNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommIOSNotifications.h; path = Comm/CommIOSNotifications/CommIOSNotifications.h; sourceTree = "<group>"; };
 		CB99DB4B2C45326C00B8055E /* NotificationsInboundKeysProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotificationsInboundKeysProvider.h; path = Notifications/BackgroundDataStorage/NotificationsInboundKeysProvider.h; sourceTree = "<group>"; };
 		CB99DB4C2C45327B00B8055E /* NotificationsInboundKeysProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NotificationsInboundKeysProvider.mm; path = Comm/NotificationsInboundKeysProvider.mm; sourceTree = "<group>"; };
 		CBA5F8832B6979ED005BE700 /* SQLiteConnectionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteConnectionManager.h; sourceTree = "<group>"; };
 		CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteConnectionManager.cpp; sourceTree = "<group>"; };
 		CBA784382B28AC4300E9F419 /* CommServicesAuthMetadataEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommServicesAuthMetadataEmitter.h; sourceTree = "<group>"; };
 		CBAAA46E2B459181007599DA /* BackupOperationsExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BackupOperationsExecutor.cpp; path = PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp; sourceTree = "<group>"; };
 		CBAAA46F2B459181007599DA /* BackupOperationsExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BackupOperationsExecutor.h; path = PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.h; sourceTree = "<group>"; };
 		CBAB63872BFCB071003B089F /* EntryStoreOperations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EntryStoreOperations.h; sourceTree = "<group>"; };
 		CBAB63882BFCB087003B089F /* EntryStore.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = EntryStore.cpp; path = PersistentStorageUtilities/DataStores/EntryStore.cpp; sourceTree = "<group>"; };
 		CBAB63892BFCB087003B089F /* EntryStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EntryStore.h; path = PersistentStorageUtilities/DataStores/EntryStore.h; sourceTree = "<group>"; };
 		CBB0DF5E2B767FDF008E22FF /* CommMMKV.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommMMKV.h; sourceTree = "<group>"; };
 		CBB0DF5F2B768007008E22FF /* CommMMKV.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommMMKV.mm; path = Comm/CommMMKV.mm; sourceTree = "<group>"; };
 		CBCA09042A8E0E6B00F75B3E /* StaffUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StaffUtils.h; sourceTree = "<group>"; };
 		CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StaffUtils.cpp; sourceTree = "<group>"; };
 		CBCF57AB2B05096F00EC4BC0 /* AESCryptoModuleObjCCompat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AESCryptoModuleObjCCompat.h; path = Comm/CommAESCryptoUtils/AESCryptoModuleObjCCompat.h; sourceTree = "<group>"; };
 		CBCF984D2BA499DA00DBC3D9 /* CommIOSServicesClient.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSServicesClient.mm; path = Comm/CommIOSServices/CommIOSServicesClient.mm; sourceTree = "<group>"; };
 		CBCF984E2BA499DA00DBC3D9 /* CommIOSServicesClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommIOSServicesClient.h; path = Comm/CommIOSServices/CommIOSServicesClient.h; sourceTree = "<group>"; };
 		CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlobalDBSingleton.h; sourceTree = "<group>"; };
 		CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GlobalDBSingleton.mm; path = Comm/GlobalDBSingleton.mm; sourceTree = "<group>"; };
 		CBF9DAE22B595934000EE771 /* EntityQueryHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EntityQueryHelpers.h; sourceTree = "<group>"; };
 		CBFBEEB82B4ED90600729F1D /* RustBackupExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustBackupExecutor.cpp; sourceTree = "<group>"; };
 		CBFBEEB92B4ED90600729F1D /* RustBackupExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustBackupExecutor.h; sourceTree = "<group>"; };
 		CBFE58272885852B003B94C9 /* ThreadOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadOperations.h; path = PersistentStorageUtilities/ThreadOperationsUtilities/ThreadOperations.h; sourceTree = "<group>"; };
 		CBFE58282885852B003B94C9 /* ThreadOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadOperations.cpp; path = PersistentStorageUtilities/ThreadOperationsUtilities/ThreadOperations.cpp; sourceTree = "<group>"; };
 		DFD5E77A2B05181400C32B6A /* RustSecureStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustSecureStore.h; sourceTree = "<group>"; };
 		DFD5E77B2B05181400C32B6A /* RustSecureStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustSecureStore.cpp; sourceTree = "<group>"; };
 		DFD5E77D2B05264000C32B6A /* AESCrypto.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AESCrypto.mm; path = Comm/AESCrypto.mm; sourceTree = "<group>"; };
 		DFD5E7802B05264F00C32B6A /* AESCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AESCrypto.h; sourceTree = "<group>"; };
 		DFD5E7842B052B1400C32B6A /* RustAESCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustAESCrypto.cpp; sourceTree = "<group>"; };
 		DFD5E7852B052B1400C32B6A /* RustAESCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustAESCrypto.h; sourceTree = "<group>"; };
 		F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Comm.debug.xcconfig"; path = "Target Support Files/Pods-Comm/Pods-Comm.debug.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 		13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				8B99BAAC28D50F3000EB5ADB /* libnative_rust_library.a in Frameworks */,
 				7F761E602201141E001B6FB7 /* JavaScriptCore.framework in Frameworks */,
 				D7DB6E0F85B2DBE15B01EC21 /* libPods-Comm.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		713EE40326C6676B003D7C48 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		724995CE27B4103A00323FCE /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				724995FB27BA9E8D00323FCE /* UserNotifications.framework in Frameworks */,
 				F02C296C528B51ADAB5AA19D /* libPods-NotificationService.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		13B07FAE1A68108700A75B9A /* Comm */ = {
 			isa = PBXGroup;
 			children = (
 				71B8CCB626BD30EC0040C0A2 /* CommCoreImplementations */,
 				7F788C2B248AA2130098F071 /* SplashScreen.storyboard */,
 				7FCFD8BD1E81B8DF00629B0E /* Comm.entitlements */,
 				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
 				13B07FB01A68108700A75B9A /* AppDelegate.mm */,
 				13B07FB51A68108700A75B9A /* Images.xcassets */,
 				7F554F822332D58B007CB9F7 /* Info.debug.plist */,
 				13B07FB61A68108700A75B9A /* Info.release.plist */,
 				13B07FB71A68108700A75B9A /* main.m */,
 				7FCEA2DC2444010B004017B1 /* Comm-Bridging-Header.h */,
 				7F26E81B24440D87004049C6 /* dummy.swift */,
 			);
 			name = Comm;
 			sourceTree = "<group>";
 		};
 		5F5A6FB2C6AD630620BBF58C /* NotificationService */ = {
 			isa = PBXGroup;
 			children = (
 				769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */,
 			);
 			name = NotificationService;
 			sourceTree = "<group>";
 		};
 		6534411766BE4CA4B0AB0A78 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
 				7FA2DCDC293E62F500991BA4 /* CommIcons.ttf */,
 				7FA2DCDD293E62F500991BA4 /* SWMansionIcons.ttf */,
 				7F8D601F26535E060053CB29 /* Anaheim-Regular.ttf */,
 				7F8D602026535E060053CB29 /* OpenSans-Regular.ttf */,
 				B71AFF1E265EDD8600B22352 /* IBMPlexSans-Medium.ttf */,
 				7F8D601E26535E060053CB29 /* OpenSans-Semibold.ttf */,
 				7F8D602726535EEE0053CB29 /* IBMPlexSans-Bold.ttf */,
 				7F8D602626535EEE0053CB29 /* IBMPlexSans-Regular.ttf */,
 			);
 			name = Resources;
 			sourceTree = "<group>";
 		};
 		713EE40726C6676B003D7C48 /* CommTests */ = {
 			isa = PBXGroup;
 			children = (
 				713EE40A26C6676B003D7C48 /* Info.plist */,
 			);
 			path = CommTests;
 			sourceTree = "<group>";
 		};
 		71B8CCB626BD30EC0040C0A2 /* CommCoreImplementations */ = {
 			isa = PBXGroup;
 			children = (
 				CB99DB4C2C45327B00B8055E /* NotificationsInboundKeysProvider.mm */,
 				CBCF984C2BA499C200DBC3D9 /* CommIOSServices */,
 				CBB0DF5F2B768007008E22FF /* CommMMKV.mm */,
 				CB74AB1B2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm */,
 				DFD5E77D2B05264000C32B6A /* AESCrypto.mm */,
 				CBCF57A92B05091D00EC4BC0 /* CommAESCryptoUtils */,
 				CB90951729531647002F2A7F /* CommIOSNotifications */,
 				8E43C32E291E5B9D009378F5 /* TerminateApp.h */,
 				8E43C32B291E5B4A009378F5 /* TerminateApp.mm */,
 				CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */,
 				CB38B4782877177B00171182 /* TemporaryMessageStorage */,
 				71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */,
 				71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */,
 				71142A7526C2650A0039DCBD /* CommSecureStoreIOSWrapper.h */,
 				71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */,
 				71CA4AEA262F230A00835C89 /* Tools.h */,
 				71CA4AEB262F236100835C89 /* Tools.mm */,
 				71CA4A63262DA8E500835C89 /* Logger.mm */,
 			);
 			name = CommCoreImplementations;
 			sourceTree = "<group>";
 		};
 		71BE84362636A944002849D2 /* cpp */ = {
 			isa = PBXGroup;
 			children = (
 				71BE84372636A944002849D2 /* CommonCpp */,
 			);
 			name = cpp;
 			path = ../cpp;
 			sourceTree = "<group>";
 		};
 		71BE84372636A944002849D2 /* CommonCpp */ = {
 			isa = PBXGroup;
 			children = (
 				CB24361429A3978800FEC4E1 /* Notifications */,
 				71F971B4270726C000DDC5BF /* _generated */,
 				71BF5B6A26B3FCFF00EDE27D /* CryptoTools */,
 				71BE84382636A944002849D2 /* Tools */,
 				71BE843A2636A944002849D2 /* NativeModules */,
 				71BE843F2636A944002849D2 /* DatabaseManagers */,
 			);
 			path = CommonCpp;
 			sourceTree = "<group>";
 		};
 		71BE84382636A944002849D2 /* Tools */ = {
 			isa = PBXGroup;
 			children = (
 				CBB0DF5E2B767FDF008E22FF /* CommMMKV.h */,
 				DFD5E7802B05264F00C32B6A /* AESCrypto.h */,
 				CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */,
 				CBCA09042A8E0E6B00F75B3E /* StaffUtils.h */,
 				7FBB2A7A29EEA2A4002C6493 /* Base64.cpp */,
 				7FBB2A7929EA752D002C6493 /* Base64.h */,
 				71B8CCBD26BD4DEB0040C0A2 /* CommSecureStore.h */,
 				718DE99C2653D41C00365824 /* WorkerThread.cpp */,
 				718DE99D2653D41C00365824 /* WorkerThread.h */,
 				71BE84392636A944002849D2 /* Logger.h */,
 				71DC160C270C43D300822863 /* PlatformSpecificTools.h */,
 			);
 			path = Tools;
 			sourceTree = "<group>";
 		};
 		71BE843A2636A944002849D2 /* NativeModules */ = {
 			isa = PBXGroup;
 			children = (
 				CBAB63872BFCB071003B089F /* EntryStoreOperations.h */,
 				B3B02EBE2B8538860020D118 /* CommunityStoreOperations.h */,
 				34329B3E2B9EBD3400233438 /* IntegrityStoreOperations.h */,
 				8E2CC2562B5C999A000C94D6 /* KeyserverStoreOperations.h */,
 				CBA784382B28AC4300E9F419 /* CommServicesAuthMetadataEmitter.h */,
 				8E3994562B039A9300D5E950 /* UserStoreOperations.h */,
 				8EA59BD22A6E800100EB4F53 /* NativeModuleUtils.h */,
 				8EF775672A74032C0046A385 /* CommRustModule.cpp */,
 				8EF775662A74032C0046A385 /* CommRustModule.h */,
 				8EE6E4A02A39CCAB00AE6BCD /* DraftStoreOperations.h */,
 				8EE6E49F2A39CCAB00AE6BCD /* ReportStoreOperations.h */,
 				CB2688FF2A2DF56000EC7300 /* CommConstants.cpp */,
 				CB2688FE2A2DF55F00EC7300 /* CommConstants.h */,
 				CBED0E2C284E086100CD3863 /* PersistentStorageUtilities */,
 				726E5D722731A4240032361D /* InternalModules */,
 				71BE843C2636A944002849D2 /* CommCoreModule.cpp */,
 				8BC9568429FC49B00060AE4A /* JSIRust.cpp */,
 				8BC9568329FC49920060AE4A /* JSIRust.h */,
 				71BE843E2636A944002849D2 /* CommCoreModule.h */,
 				7FBB2A7329E944FD002C6493 /* CommUtilsModule.cpp */,
 				7FBB2A7429E9450E002C6493 /* CommUtilsModule.h */,
 				34055C162BAD31BD0008E713 /* SyncedMetadataStoreOperations.h */,
 				B7055C6B26E477CF00BE0548 /* MessageStoreOperations.h */,
 				B7906F692720905A009BBBF5 /* ThreadStoreOperations.h */,
 				34FF25A62BB738DC0075EC40 /* AuxUserStoreOperations.h */,
 				34BE12762BC3F3D100CCAD11 /* ThreadActivityStoreOperations.h */,
 			);
 			path = NativeModules;
 			sourceTree = "<group>";
 		};
 		71BE843F2636A944002849D2 /* DatabaseManagers */ = {
 			isa = PBXGroup;
 			children = (
 				CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */,
 				CB3CCAFF2B7246F400793640 /* NativeSQLiteConnectionManager.h */,
 				CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */,
 				CBA5F8832B6979ED005BE700 /* SQLiteConnectionManager.h */,
 				8E86A6D229537EBB000BBE7D /* DatabaseManager.cpp */,
 				71BE84402636A944002849D2 /* DatabaseQueryExecutor.h */,
 				71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */,
 				71BE84422636A944002849D2 /* SQLiteQueryExecutor.h */,
 				71BE84432636A944002849D2 /* DatabaseManager.h */,
 				71BE84442636A944002849D2 /* entities */,
 			);
 			path = DatabaseManagers;
 			sourceTree = "<group>";
 		};
 		71BE84442636A944002849D2 /* entities */ = {
 			isa = PBXGroup;
 			children = (
+				0E02676D2D81EAD800788249 /* DMOperation.h */,
 				816D2D5B2C480E9E001C0B67 /* MessageSearchResult.h */,
 				CB01F0C32B67F3970089E1F9 /* SQLiteStatementWrapper.cpp */,
 				CB01F0C12B67EF470089E1F9 /* SQLiteDataConverters.cpp */,
 				CB01F0C02B67CDC20089E1F9 /* SQLiteDataConverters.h */,
 				CB01F0BF2B67CDC20089E1F9 /* SQLiteStatementWrapper.h */,
 				CBF9DAE22B595934000EE771 /* EntityQueryHelpers.h */,
 				34329B452B9EC96200233438 /* IntegrityThreadHash.h */,
 				B7906F6A27209091009BBBF5 /* OlmPersistAccount.h */,
 				B7906F6B27209091009BBBF5 /* OlmPersistSession.h */,
 				B7906F6C27209091009BBBF5 /* Thread.h */,
 				71BE84452636A944002849D2 /* Draft.h */,
 				B70FBC1226B047050040F480 /* Message.h */,
 				B7E937CA26F448E700022A7C /* Media.h */,
 				2DDA0A22FECC9DAA5C19C35D /* Metadata.h */,
 			);
 			path = entities;
 			sourceTree = "<group>";
 		};
 		71BF5B6A26B3FCFF00EDE27D /* CryptoTools */ = {
 			isa = PBXGroup;
 			children = (
 				75291F0328F9A0AE00F4C80E /* DeviceID.cpp */,
 				75291F0228F9A09E00F4C80E /* DeviceID.h */,
 				71BF5B7B26BBDA6100EDE27D /* CryptoModule.cpp */,
 				71BF5B7A26BBDA6000EDE27D /* CryptoModule.h */,
 				71BF5B6F26B3FF0900EDE27D /* Session.cpp */,
 				71BF5B7026B3FF0900EDE27D /* Session.h */,
 				71BF5B7226B3FFBC00EDE27D /* Persist.h */,
 				71BF5B7326B401D300EDE27D /* Tools.cpp */,
 				71BF5B7426B401D300EDE27D /* Tools.h */,
 			);
 			path = CryptoTools;
 			sourceTree = "<group>";
 		};
 		71F971B4270726C000DDC5BF /* _generated */ = {
 			isa = PBXGroup;
 			children = (
 				8EA59BD72A73DAB000EB4F53 /* rustJSI-generated.cpp */,
 				8EA59BD82A73DAB000EB4F53 /* rustJSI.h */,
 				7FE4D9F4291DFE9300667BF6 /* commJSI-generated.cpp */,
 				7FE4D9F3291DFE9300667BF6 /* commJSI.h */,
 				7FBB2A7529E94539002C6493 /* utilsJSI-generated.cpp */,
 				7FBB2A7729E94541002C6493 /* utilsJSI.h */,
 			);
 			path = _generated;
 			sourceTree = "<group>";
 		};
 		724995D227B4103A00323FCE /* NotificationService */ = {
 			isa = PBXGroup;
 			children = (
 				CB30C12327D0ACF700FBE8DE /* NotificationService.entitlements */,
 				724995D327B4103A00323FCE /* NotificationService.h */,
 				724995D427B4103A00323FCE /* NotificationService.mm */,
 				724995D627B4103A00323FCE /* Info.plist */,
 			);
 			path = NotificationService;
 			sourceTree = "<group>";
 		};
 		726E5D722731A4240032361D /* InternalModules */ = {
 			isa = PBXGroup;
 			children = (
 				8B38121529CE5742000C52E9 /* RustPromiseManager.cpp */,
 				8B652FA1295EA6B8009F8163 /* RustPromiseManager.h */,
 				CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */,
 			);
 			path = InternalModules;
 			sourceTree = "<group>";
 		};
 		7FF0870B1E833C3F000A1ACF /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
 				8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */,
 				CB3C621327CE66540054F24C /* libEXSecureStore.a */,
 				724995FA27BA9E8C00323FCE /* UserNotifications.framework */,
 				711CF80E25DC096000A00FBD /* libFolly.a */,
 				7F761E292201141E001B6FB7 /* JavaScriptCore.framework */,
 				994BEBDD4E4959F69CEA0BC3 /* libPods-Comm.a */,
 				3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
 		};
 		83CBB9F61A601CBA00E9B192 = {
 			isa = PBXGroup;
 			children = (
 				CB3220912BDA66B900DB6C5C /* PrivacyInfo.xcprivacy */,
 				8B99AF6B28D50D4800EB5ADB /* native_rust_library */,
 				71BE84362636A944002849D2 /* cpp */,
 				13B07FAE1A68108700A75B9A /* Comm */,
 				713EE40726C6676B003D7C48 /* CommTests */,
 				724995D227B4103A00323FCE /* NotificationService */,
 				83CBBA001A601CBA00E9B192 /* Products */,
 				6534411766BE4CA4B0AB0A78 /* Resources */,
 				7FF0870B1E833C3F000A1ACF /* Frameworks */,
 				D533B93718E3B9684B508006 /* Pods */,
 				AFF3F1F76178B42122C79BDE /* ExpoModulesProviders */,
 			);
 			indentWidth = 2;
 			sourceTree = "<group>";
 			tabWidth = 2;
 		};
 		83CBBA001A601CBA00E9B192 /* Products */ = {
 			isa = PBXGroup;
 			children = (
 				13B07F961A680F5B00A75B9A /* Comm.app */,
 				713EE40626C6676B003D7C48 /* CommTests.xctest */,
 				724995D127B4103A00323FCE /* NotificationService.appex */,
 			);
 			name = Products;
 			sourceTree = "<group>";
 		};
 		8B99AF6B28D50D4800EB5ADB /* native_rust_library */ = {
 			isa = PBXGroup;
 			children = (
 				CBFBEEB82B4ED90600729F1D /* RustBackupExecutor.cpp */,
 				CBFBEEB92B4ED90600729F1D /* RustBackupExecutor.h */,
 				CB74AB1E2B2B0C0900CBB494 /* RustCSAMetadataEmitter.cpp */,
 				CB74AB1F2B2B0C0900CBB494 /* RustCSAMetadataEmitter.h */,
 				DFD5E7842B052B1400C32B6A /* RustAESCrypto.cpp */,
 				DFD5E7852B052B1400C32B6A /* RustAESCrypto.h */,
 				DFD5E77B2B05181400C32B6A /* RustSecureStore.cpp */,
 				DFD5E77A2B05181400C32B6A /* RustSecureStore.h */,
 				8B652FA4295EA9F1009F8163 /* RustCallback.h */,
 				8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */,
 				8B99AF6D28D50D4800EB5ADB /* lib.rs.h */,
 				8B99B59928D50D4900EB5ADB /* cxx.h */,
 				8B652FA5295EAA5B009F8163 /* RustCallback.cpp */,
 			);
 			name = native_rust_library;
 			path = ../native_rust_library;
 			sourceTree = "<group>";
 		};
 		8EA59BD02A6E786200EB4F53 /* DataStores */ = {
 			isa = PBXGroup;
 			children = (
 				816D2D582C480E60001C0B67 /* MessageSearchStore.cpp */,
 				816D2D592C480E60001C0B67 /* MessageSearchStore.h */,
 				CBAB63882BFCB087003B089F /* EntryStore.cpp */,
 				CBAB63892BFCB087003B089F /* EntryStore.h */,
 				34FF25B82BB753B30075EC40 /* AuxUserStore.h */,
 				34FF25B92BB757860075EC40 /* AuxUserStore.cpp */,
 				8E2CC2582B5C99B0000C94D6 /* KeyserverStore.cpp */,
 				8E2CC2572B5C99B0000C94D6 /* KeyserverStore.h */,
 				B3B02EBD2B8536560020D118 /* CommunityStore.cpp */,
 				B3B02EBC2B8534C00020D118 /* CommunityStore.h */,
 				34329B3F2B9EBFCE00233438 /* IntegrityStore.cpp */,
 				34329B402B9EBFCE00233438 /* IntegrityStore.h */,
 				8E3994532B039A7C00D5E950 /* UserStore.cpp */,
 				8E3994542B039A7C00D5E950 /* UserStore.h */,
 				8EF7756F2A751B780046A385 /* ReportStore.cpp */,
 				8EF775702A751B780046A385 /* ReportStore.h */,
 				8EF7756D2A7513F40046A385 /* MessageStore.cpp */,
 				8EF7756C2A7513F40046A385 /* MessageStore.h */,
 				8EF775692A7433630046A385 /* ThreadStore.cpp */,
 				8EF7756A2A7433630046A385 /* ThreadStore.h */,
 				8EA59BD42A6E8E0400EB4F53 /* DraftStore.cpp */,
 				8EA59BD52A6E8E0400EB4F53 /* DraftStore.h */,
 				8EA59BD32A6E8CB700EB4F53 /* BaseDataStore.h */,
 				34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */,
 				34055C132BAD31AB0008E713 /* SyncedMetadataStore.h */,
 				34BE127C2BC3F78C00CCAD11 /* ThreadActivityStore.cpp */,
 				34BE127B2BC3F78B00CCAD11 /* ThreadActivityStore.h */,
 			);
 			name = DataStores;
 			sourceTree = "<group>";
 		};
 		AFF3F1F76178B42122C79BDE /* ExpoModulesProviders */ = {
 			isa = PBXGroup;
 			children = (
 				E75E6E4967CE9A8BBA89ED86 /* Comm */,
 				5F5A6FB2C6AD630620BBF58C /* NotificationService */,
 			);
 			name = ExpoModulesProviders;
 			sourceTree = "<group>";
 		};
 		CB24361429A3978800FEC4E1 /* Notifications */ = {
 			isa = PBXGroup;
 			children = (
 				CB24361529A3979500FEC4E1 /* BackgroundDataStorage */,
 			);
 			name = Notifications;
 			sourceTree = "<group>";
 		};
 		CB24361529A3979500FEC4E1 /* BackgroundDataStorage */ = {
 			isa = PBXGroup;
 			children = (
 				CB99DB4B2C45326C00B8055E /* NotificationsInboundKeysProvider.h */,
 				CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */,
 				CB24361629A397AB00FEC4E1 /* NotificationsCryptoModule.h */,
 			);
 			name = BackgroundDataStorage;
 			sourceTree = "<group>";
 		};
 		CB38B4782877177B00171182 /* TemporaryMessageStorage */ = {
 			isa = PBXGroup;
 			children = (
 				CB38B47F28771A3B00171182 /* TemporaryMessageStorage.mm */,
 				CB38B47E287719C500171182 /* TemporaryMessageStorage.h */,
 				CB38B47D2877194100171182 /* EncryptedFileUtils.mm */,
 				CB38B47C2877190100171182 /* EncryptedFileUtils.h */,
 				CB38B47B287718A200171182 /* NonBlockingLock.mm */,
 				CB38B4792877179A00171182 /* NonBlockingLock.h */,
 			);
 			name = TemporaryMessageStorage;
 			sourceTree = "<group>";
 		};
 		CB38F2AC286C6C010010535C /* MessageOperationsUtilities */ = {
 			isa = PBXGroup;
 			children = (
 				CB38F2AF286C6C870010535C /* MessageOperationsUtilities.cpp */,
 				CB38F2B0286C6C870010535C /* MessageOperationsUtilities.h */,
 				CB38F2AE286C6C870010535C /* MessageSpecs.h */,
 				CB38F2AD286C6C4B0010535C /* MessageSpecs */,
 			);
 			name = MessageOperationsUtilities;
 			sourceTree = "<group>";
 		};
 		CB38F2AD286C6C4B0010535C /* MessageSpecs */ = {
 			isa = PBXGroup;
 			children = (
 				7F446E2329C3B2BE00670288 /* SidebarSourceMessageSpec.h */,
 				CB38F2B5286C6C970010535C /* ChangeRoleMessageSpec.h */,
 				CB38F2B8286C6C970010535C /* ChangeSettingsMessageSpec.h */,
 				CB38F2BA286C6C970010535C /* CreateEntryMessageSpec.h */,
 				CB38F2B4286C6C970010535C /* CreateSidebarMessageSpec.h */,
 				CB38F2BC286C6C970010535C /* CreateSubThreadMessageSpec.h */,
 				CB38F2B2286C6C970010535C /* CreateThreadMessageSpec.h */,
 				CB38F2BE286C6C980010535C /* DeleteEntryMessageSpec.h */,
 				CB38F2BB286C6C970010535C /* EditEntryMessageSpec.h */,
 				CB38F2B7286C6C970010535C /* MessageSpec.h */,
 				CB38F2BD286C6C970010535C /* MultimediaMessageSpec.h */,
 				7F446E2229C3AF3800670288 /* ReactionMessageSpec.h */,
 				CB38F2B6286C6C970010535C /* RestoreEntryMessageSpec.h */,
 				CB38F2B3286C6C970010535C /* TextMessageSpec.h */,
 				CB38F2B9286C6C970010535C /* UnsupportedMessageSpec.h */,
 				CB38F2BF286C6C980010535C /* UpdateRelationshipMessageSpec.h */,
 			);
 			name = MessageSpecs;
 			sourceTree = "<group>";
 		};
 		CB90951729531647002F2A7F /* CommIOSNotifications */ = {
 			isa = PBXGroup;
 			children = (
 				CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */,
 				CB7EF17C295C580500B17035 /* CommIOSNotificationsBridgeQueue.h */,
 				CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */,
 				CB90951929531663002F2A7F /* CommIOSNotifications.h */,
 			);
 			name = CommIOSNotifications;
 			sourceTree = "<group>";
 		};
 		CBAAA46D2B45915F007599DA /* BackupOperationsUtilities */ = {
 			isa = PBXGroup;
 			children = (
 				CBAAA46E2B459181007599DA /* BackupOperationsExecutor.cpp */,
 				CBAAA46F2B459181007599DA /* BackupOperationsExecutor.h */,
 			);
 			name = BackupOperationsUtilities;
 			sourceTree = "<group>";
 		};
 		CBCF57A92B05091D00EC4BC0 /* CommAESCryptoUtils */ = {
 			isa = PBXGroup;
 			children = (
 				CBCF57AB2B05096F00EC4BC0 /* AESCryptoModuleObjCCompat.h */,
 			);
 			name = CommAESCryptoUtils;
 			sourceTree = "<group>";
 		};
 		CBCF984C2BA499C200DBC3D9 /* CommIOSServices */ = {
 			isa = PBXGroup;
 			children = (
 				CBCF984E2BA499DA00DBC3D9 /* CommIOSServicesClient.h */,
 				CBCF984D2BA499DA00DBC3D9 /* CommIOSServicesClient.mm */,
 			);
 			name = CommIOSServices;
 			sourceTree = "<group>";
 		};
 		CBED0E2C284E086100CD3863 /* PersistentStorageUtilities */ = {
 			isa = PBXGroup;
 			children = (
 				CBAAA46D2B45915F007599DA /* BackupOperationsUtilities */,
 				8EA59BD02A6E786200EB4F53 /* DataStores */,
 				CBFE582628858512003B94C9 /* ThreadOperationsUtilities */,
 				CB38F2AC286C6C010010535C /* MessageOperationsUtilities */,
 			);
 			name = PersistentStorageUtilities;
 			sourceTree = "<group>";
 		};
 		CBFE582628858512003B94C9 /* ThreadOperationsUtilities */ = {
 			isa = PBXGroup;
 			children = (
 				CBFE58282885852B003B94C9 /* ThreadOperations.cpp */,
 				CBFE58272885852B003B94C9 /* ThreadOperations.h */,
 			);
 			name = ThreadOperationsUtilities;
 			sourceTree = "<group>";
 		};
 		D533B93718E3B9684B508006 /* Pods */ = {
 			isa = PBXGroup;
 			children = (
 				F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */,
 				C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */,
 				891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */,
 				913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */,
 			);
 			path = Pods;
 			sourceTree = "<group>";
 		};
 		E75E6E4967CE9A8BBA89ED86 /* Comm */ = {
 			isa = PBXGroup;
 			children = (
 				3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */,
 			);
 			name = Comm;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
 		13B07F861A680F5B00A75B9A /* Comm */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Comm" */;
 			buildPhases = (
 				02DE093B3C1DDF10C1FA3E9C /* [CP] Check Pods Manifest.lock */,
 				8BF9F24E28B795E200E20C13 /* Build Rust library */,
 				13B07F871A680F5B00A75B9A /* Sources */,
 				13B07F8C1A680F5B00A75B9A /* Frameworks */,
 				13B07F8E1A680F5B00A75B9A /* Resources */,
 				00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
 				DB38BFA0686C805CE44F051F /* [CP] Copy Pods Resources */,
 				EA2E8897D838D7F3E680EACE /* [CP] Embed Pods Frameworks */,
 				724995DA27B4103A00323FCE /* Embed App Extensions */,
 			);
 			buildRules = (
 			);
 			dependencies = (
 				724995D827B4103A00323FCE /* PBXTargetDependency */,
 			);
 			name = Comm;
 			productName = "Hello World";
 			productReference = 13B07F961A680F5B00A75B9A /* Comm.app */;
 			productType = "com.apple.product-type.application";
 		};
 		713EE40526C6676B003D7C48 /* CommTests */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 713EE40F26C6676B003D7C48 /* Build configuration list for PBXNativeTarget "CommTests" */;
 			buildPhases = (
 				713EE40226C6676B003D7C48 /* Sources */,
 				713EE40326C6676B003D7C48 /* Frameworks */,
 				713EE40426C6676B003D7C48 /* Resources */,
 			);
 			buildRules = (
 			);
 			dependencies = (
 				713EE40C26C6676B003D7C48 /* PBXTargetDependency */,
 			);
 			name = CommTests;
 			productName = CommTests;
 			productReference = 713EE40626C6676B003D7C48 /* CommTests.xctest */;
 			productType = "com.apple.product-type.bundle.unit-test";
 		};
 		724995D027B4103A00323FCE /* NotificationService */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 724995DD27B4103A00323FCE /* Build configuration list for PBXNativeTarget "NotificationService" */;
 			buildPhases = (
 				6735FA74B2C82E3B27E18258 /* [CP] Check Pods Manifest.lock */,
 				724995CD27B4103A00323FCE /* Sources */,
 				724995CE27B4103A00323FCE /* Frameworks */,
 				724995CF27B4103A00323FCE /* Resources */,
 				E6221695BEF4548AF41DD8EB /* [CP] Copy Pods Resources */,
 			);
 			buildRules = (
 			);
 			dependencies = (
 			);
 			name = NotificationService;
 			productName = NotificationService;
 			productReference = 724995D127B4103A00323FCE /* NotificationService.appex */;
 			productType = "com.apple.product-type.app-extension";
 		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
 		83CBB9F71A601CBA00E9B192 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
 				LastUpgradeCheck = 1150;
 				ORGANIZATIONNAME = "Comm Technologies, Inc.";
 				TargetAttributes = {
 					13B07F861A680F5B00A75B9A = {
 						DevelopmentTeam = H98Y8MH53M;
 						LastSwiftMigration = 1140;
 						ProvisioningStyle = Automatic;
 						SystemCapabilities = {
 							com.apple.BackgroundModes = {
 								enabled = 1;
 							};
 							com.apple.GameCenter = {
 								enabled = 0;
 							};
 							com.apple.InAppPurchase = {
 								enabled = 0;
 							};
 							com.apple.Keychain = {
 								enabled = 1;
 							};
 							com.apple.Push = {
 								enabled = 1;
 							};
 							com.apple.SafariKeychain = {
 								enabled = 1;
 							};
 						};
 					};
 					713EE40526C6676B003D7C48 = {
 						CreatedOnToolsVersion = 12.5.1;
 						ProvisioningStyle = Automatic;
 						TestTargetID = 13B07F861A680F5B00A75B9A;
 					};
 					724995D027B4103A00323FCE = {
 						CreatedOnToolsVersion = 13.0;
 						DevelopmentTeam = H98Y8MH53M;
 						ProvisioningStyle = Automatic;
 					};
 				};
 			};
 			buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Comm" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
 			knownRegions = (
 				English,
 				en,
 				Base,
 			);
 			mainGroup = 83CBB9F61A601CBA00E9B192;
 			productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
 				13B07F861A680F5B00A75B9A /* Comm */,
 				713EE40526C6676B003D7C48 /* CommTests */,
 				724995D027B4103A00323FCE /* NotificationService */,
 			);
 		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
 		13B07F8E1A680F5B00A75B9A /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				7F8D602926535F2A0053CB29 /* IBMPlexSans-Regular.ttf in Resources */,
 				CB3220922BDA66B900DB6C5C /* PrivacyInfo.xcprivacy in Resources */,
 				7F8D602826535F240053CB29 /* IBMPlexSans-Bold.ttf in Resources */,
 				7F8D602126535E060053CB29 /* OpenSans-Semibold.ttf in Resources */,
 				7FA2DCDE293E62F500991BA4 /* CommIcons.ttf in Resources */,
 				13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
 				7F788C2C248AA2140098F071 /* SplashScreen.storyboard in Resources */,
 				7F8D602226535E060053CB29 /* Anaheim-Regular.ttf in Resources */,
 				7FA2DCDF293E62F500991BA4 /* SWMansionIcons.ttf in Resources */,
 				B71AFF1F265EDD8600B22352 /* IBMPlexSans-Medium.ttf in Resources */,
 				7F8D602326535E060053CB29 /* OpenSans-Regular.ttf in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		713EE40426C6676B003D7C48 /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		724995CF27B4103A00323FCE /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				CB3220932BDA66B900DB6C5C /* PrivacyInfo.xcprivacy in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
 		00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 				"$(SRCROOT)/.xcode.env.local",
 				"$(SRCROOT)/.xcode.env",
 			);
 			name = "Bundle React Native code and images";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
 		};
 		02DE093B3C1DDF10C1FA3E9C /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
 			);
 			inputPaths = (
 				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
 				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputFileListPaths = (
 			);
 			outputPaths = (
 				"$(DERIVED_FILE_DIR)/Pods-Comm-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		6735FA74B2C82E3B27E18258 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
 			);
 			inputPaths = (
 				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
 				"${PODS_ROOT}/Manifest.lock",
 			);
 			name = "[CP] Check Pods Manifest.lock";
 			outputFileListPaths = (
 			);
 			outputPaths = (
 				"$(DERIVED_FILE_DIR)/Pods-NotificationService-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 		8BF9F24E28B795E200E20C13 /* Build Rust library */ = {
 			isa = PBXShellScriptBuildPhase;
 			alwaysOutOfDate = 1;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
 			);
 			inputPaths = (
 			);
 			name = "Build Rust library";
 			outputFileListPaths = (
 			);
 			outputPaths = (
 				"${SRCROOT}/../native_rust_library/lib.rs.cc",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "${SRCROOT}/../../scripts/build-rust-native-library.sh\n";
 		};
 		DB38BFA0686C805CE44F051F /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-resources.sh",
 				"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 		E6221695BEF4548AF41DD8EB /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-NotificationService/Pods-NotificationService-resources.sh",
 				"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-launcher/EXDevLauncher.bundle",
 				"${PODS_CONFIGURATION_BUILD_DIR}/expo-dev-menu/EXDevMenu.bundle",
 			);
 			name = "[CP] Copy Pods Resources";
 			outputPaths = (
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevLauncher.bundle",
 				"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXDevMenu.bundle",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NotificationService/Pods-NotificationService-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 		EA2E8897D838D7F3E680EACE /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 				"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-frameworks.sh",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/ffmpegkit.framework/ffmpegkit",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavcodec.framework/libavcodec",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavdevice.framework/libavdevice",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavfilter.framework/libavfilter",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavformat.framework/libavformat",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libavutil.framework/libavutil",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libswresample.framework/libswresample",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/ffmpeg-kit-ios-min/libswscale.framework/libswscale",
 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
 			);
 			name = "[CP] Embed Pods Frameworks";
 			outputPaths = (
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ffmpegkit.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavcodec.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavdevice.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavfilter.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavformat.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libavutil.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libswresample.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libswscale.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Comm/Pods-Comm-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
 		13B07F871A680F5B00A75B9A /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				CBAB638A2BFCCA9B003B089F /* EntryStore.cpp in Sources */,
 				CB3CCB012B72470700793640 /* NativeSQLiteConnectionManager.cpp in Sources */,
 				CBA5F8852B6979F7005BE700 /* SQLiteConnectionManager.cpp in Sources */,
 				CB01F0C42B67F3A10089E1F9 /* SQLiteStatementWrapper.cpp in Sources */,
 				CB01F0C22B67EF5A0089E1F9 /* SQLiteDataConverters.cpp in Sources */,
 				CBAAA4702B459181007599DA /* BackupOperationsExecutor.cpp in Sources */,
 				CBCA09062A8E0E7400F75B3E /* StaffUtils.cpp in Sources */,
 				8EF7756B2A7433630046A385 /* ThreadStore.cpp in Sources */,
 				CB2689002A2DF58000EC7300 /* CommConstants.cpp in Sources */,
 				34FF25BA2BB757870075EC40 /* AuxUserStore.cpp in Sources */,
 				CB7EF17E295C674300B17035 /* CommIOSNotifications.mm in Sources */,
 				CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */,
 				34BE127D2BC3F78C00CCAD11 /* ThreadActivityStore.cpp in Sources */,
 				7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */,
 				8EF775682A74032C0046A385 /* CommRustModule.cpp in Sources */,
 				34055C152BAD31AC0008E713 /* SyncedMetadataStore.cpp in Sources */,
 				8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */,
 				CBCF984F2BA499DA00DBC3D9 /* CommIOSServicesClient.mm in Sources */,
 				B3B02EBF2B8538980020D118 /* CommunityStore.cpp in Sources */,
 				CB99DB4D2C45327C00B8055E /* NotificationsInboundKeysProvider.mm in Sources */,
 				8BC9568529FC49B00060AE4A /* JSIRust.cpp in Sources */,
 				8EA59BD92A73DAB000EB4F53 /* rustJSI-generated.cpp in Sources */,
 				CB38B48628771CDD00171182 /* TemporaryMessageStorage.mm in Sources */,
 				CB74AB202B2B0C0A00CBB494 /* RustCSAMetadataEmitter.cpp in Sources */,
 				CB38B48428771CAF00171182 /* EncryptedFileUtils.mm in Sources */,
 				CBFE58292885852B003B94C9 /* ThreadOperations.cpp in Sources */,
 				CB74AB1C2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm in Sources */,
 				8E3994552B039A7C00D5E950 /* UserStore.cpp in Sources */,
 				CBFBEEBA2B4ED90600729F1D /* RustBackupExecutor.cpp in Sources */,
 				7FBB2A7829E945C2002C6493 /* CommUtilsModule.cpp in Sources */,
 				CB38B48228771C7A00171182 /* NonBlockingLock.mm in Sources */,
 				718DE99E2653D41C00365824 /* WorkerThread.cpp in Sources */,
 				8B99BAAE28D511FF00EB5ADB /* lib.rs.cc in Sources */,
 				71CA4AEC262F236100835C89 /* Tools.mm in Sources */,
 				CBB0DF602B768007008E22FF /* CommMMKV.mm in Sources */,
 				71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */,
 				71BF5B7126B3FF0900EDE27D /* Session.cpp in Sources */,
 				8EF7756E2A7513F40046A385 /* MessageStore.cpp in Sources */,
 				8E2CC2592B5C99B0000C94D6 /* KeyserverStore.cpp in Sources */,
 				DFD5E77C2B05181400C32B6A /* RustSecureStore.cpp in Sources */,
 				71BF5B7526B401D300EDE27D /* Tools.cpp in Sources */,
 				13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
 				7FE4D9F5291DFE9300667BF6 /* commJSI-generated.cpp in Sources */,
 				8B652FA6295EAA5B009F8163 /* RustCallback.cpp in Sources */,
 				71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */,
 				7FBB2A7B29EEA2A4002C6493 /* Base64.cpp in Sources */,
 				CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */,
 				DFD5E7862B052B1400C32B6A /* RustAESCrypto.cpp in Sources */,
 				816D2D5A2C480E60001C0B67 /* MessageSearchStore.cpp in Sources */,
 				8EF775712A751B780046A385 /* ReportStore.cpp in Sources */,
 				34329B442B9EC7EC00233438 /* IntegrityStore.cpp in Sources */,
 				71CA4A64262DA8E500835C89 /* Logger.mm in Sources */,
 				71BF5B7F26BBDD7400EDE27D /* CryptoModule.cpp in Sources */,
 				CB24361829A39A2500FEC4E1 /* NotificationsCryptoModule.cpp in Sources */,
 				71BE844A2636A944002849D2 /* CommCoreModule.cpp in Sources */,
 				71D4D7CC26C50B1000FCDBCD /* CommSecureStore.mm in Sources */,
 				8B38121629CE5742000C52E9 /* RustPromiseManager.cpp in Sources */,
 				7FBB2A7629E94539002C6493 /* utilsJSI-generated.cpp in Sources */,
 				711B408425DA97F9005F8F06 /* dummy.swift in Sources */,
 				8E86A6D329537EBB000BBE7D /* DatabaseManager.cpp in Sources */,
 				CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */,
 				DFD5E77E2B05264000C32B6A /* AESCrypto.mm in Sources */,
 				8EA59BD62A6E8E0400EB4F53 /* DraftStore.cpp in Sources */,
 				13B07FC11A68108700A75B9A /* main.m in Sources */,
 				71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		713EE40226C6676B003D7C48 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		724995CD27B4103A00323FCE /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				CB99DB4E2C45329500B8055E /* NotificationsInboundKeysProvider.mm in Sources */,
 				CBCF98502BA49A0500DBC3D9 /* CommIOSServicesClient.mm in Sources */,
 				CBCA09072A8E0E7D00F75B3E /* StaffUtils.cpp in Sources */,
 				CB3C0A3B2A125C8F009BD4DA /* NotificationsCryptoModule.cpp in Sources */,
 				CB90951F29534B32002F2A7F /* CommSecureStore.mm in Sources */,
 				CB38B48728771CE500171182 /* TemporaryMessageStorage.mm in Sources */,
 				CB38B48528771CB800171182 /* EncryptedFileUtils.mm in Sources */,
 				CB38B48328771C8300171182 /* NonBlockingLock.mm in Sources */,
 				CB1648AF27CFBE6A00394D9D /* CryptoModule.cpp in Sources */,
 				CB4821AE27CFB187001AB7E1 /* Tools.cpp in Sources */,
 				CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */,
 				CBB0DF612B768007008E22FF /* CommMMKV.mm in Sources */,
 				CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */,
 				CB4821AA27CFB153001AB7E1 /* Tools.mm in Sources */,
 				CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */,
 				CB3C621127CE4A320054F24C /* Logger.mm in Sources */,
 				724995D527B4103A00323FCE /* NotificationService.mm in Sources */,
 				CB4821AF27CFB19D001AB7E1 /* PlatformSpecificTools.mm in Sources */,
 				1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
 		713EE40C26C6676B003D7C48 /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 13B07F861A680F5B00A75B9A /* Comm */;
 			targetProxy = 713EE40B26C6676B003D7C48 /* PBXContainerItemProxy */;
 		};
 		724995D827B4103A00323FCE /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 724995D027B4103A00323FCE /* NotificationService */;
 			targetProxy = 724995D727B4103A00323FCE /* PBXContainerItemProxy */;
 		};
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
 		13B07F941A680F5B00A75B9A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = F53DA7B3F26C2798DCE74A94 /* Pods-Comm.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES;
 				CODE_SIGN_ENTITLEMENTS = Comm/Comm.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEAD_CODE_STRIPPING = YES;
 				DEVELOPMENT_TEAM = H98Y8MH53M;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"COCOAPODS=1",
 					"FB_SONARKIT_ENABLED=1",
 					"SD_WEBP=1",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS",
 					"$(PODS_ROOT)/boost-for-react-native",
 					"$(SRCROOT)/../native_rust_library",
 					"$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging",
 				);
 				INFOPLIST_FILE = Comm/Info.debug.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(SDKROOT)/usr/lib/swift",
 					"$(inherited)",
 					"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/CocoaAsyncSocket\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/DVAssetLoaderDelegate\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageLoader\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageManipulator\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXKeepAwake\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXSecureStore\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/FBReactNativeSpec\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/OLMKit\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf-C++\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCClipboard\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNFS\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNFastImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNKeychain\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNVectorIcons\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeART\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeDarkMode\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardInput\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardTrackingView\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SPTPersistentCache\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher-Amalgamation\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/YogaKit\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/abseil\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/libwebp\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-video\"",
 					/usr/lib/swift,
 				);
 				"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
 					"$(inherited)",
 					"$(SRCROOT)/../native_rust_library/target/aarch64-apple-ios/debug",
 				);
 				"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
 					"$(inherited)",
 					"$(SRCROOT)/../native_rust_library/target/x86_64-apple-ios/debug",
 				);
 				OTHER_CPLUSPLUSFLAGS = (
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-DREACT_NATIVE_MINOR_VERSION=70",
 					"-fcxx-modules",
 					"-fmodules",
 				);
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-ObjC",
 					"-lc++",
 				);
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
 				PRODUCT_BUNDLE_IDENTIFIER = app.comm;
 				PRODUCT_NAME = Comm;
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_OBJC_BRIDGING_HEADER = "Comm-Bridging-Header.h";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 1;
 				USE_HEADERMAP = YES;
 				VERSIONING_SYSTEM = "apple-generic";
 			};
 			name = Debug;
 		};
 		13B07F951A680F5B00A75B9A /* Release */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = C562A7004903539402D988CE /* Pods-Comm.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES;
 				CODE_SIGN_ENTITLEMENTS = Comm/Comm.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = H98Y8MH53M;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS",
 					"$(PODS_ROOT)/boost-for-react-native",
 					"$(SRCROOT)/../native_rust_library",
 					"$(PODS_ROOT)/Headers/Private/React-bridging/react/bridging",
 				);
 				INFOPLIST_FILE = Comm/Info.release.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(SDKROOT)/usr/lib/swift",
 					"$(inherited)",
 					"\"${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/CocoaAsyncSocket\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/DVAssetLoaderDelegate\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXFont\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageLoader\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXImageManipulator\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXKeepAwake\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/EXSecureStore\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/FBReactNativeSpec\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/OLMKit\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf-C++\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RCTTypeSafety\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCClipboard\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNCMaskedView\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNFS\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNFastImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNGestureHandler\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNKeychain\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNReanimated\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNScreens\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/RNVectorIcons\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-CoreModules\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTAnimation\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTBlob\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTLinking\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTNetwork\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTSettings\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTText\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTVibration\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-hermes\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsi\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsiexecutor\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-jsinspector\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-logger\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/React-perflogger\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeART\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeDarkMode\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardInput\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/ReactNativeKeyboardTrackingView\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SPTPersistentCache\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/SQLCipher-Amalgamation\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/Yoga\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/YogaKit\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/abseil\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/fmt\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/glog\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/libevent\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/libwebp\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/lottie-react-native\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-camera\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-in-app-message\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-netinfo\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-notifications\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-safe-area-context\"",
 					"\"${PODS_CONFIGURATION_BUILD_DIR}/react-native-video\"",
 					/usr/lib/swift,
 				);
 				"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
 					"$(inherited)",
 					"$(SRCROOT)/../native_rust_library/target/aarch64-apple-ios/release",
 				);
 				"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
 					"$(inherited)",
 					"$(SRCROOT)/../native_rust_library/target/x86_64-apple-ios/release",
 				);
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CPLUSPLUSFLAGS = (
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-DREACT_NATIVE_MINOR_VERSION=70",
 					"-fcxx-modules",
 					"-fmodules",
 				);
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-ObjC",
 					"-lc++",
 				);
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
 				PRODUCT_BUNDLE_IDENTIFIER = app.comm;
 				PRODUCT_NAME = Comm;
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_OBJC_BRIDGING_HEADER = "Comm-Bridging-Header.h";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 1;
 				USE_HEADERMAP = YES;
 				VERSIONING_SYSTEM = "apple-generic";
 			};
 			name = Release;
 		};
 		713EE40D26C6676B003D7C48 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_OBJC_WEAK = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
 				);
 				INFOPLIST_FILE = CommTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 14.5;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
 				PRODUCT_BUNDLE_IDENTIFIER = swm.CommTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Comm.app/Comm";
 				USER_HEADER_SEARCH_PATHS = (
 					../../node_modules/olm/include,
 					../../node_modules/olm/lib,
 					"${PODS_ROOT}/OLMKit/include",
 					"${PODS_ROOT}/OLMKit/lib",
 				);
 			};
 			name = Debug;
 		};
 		713EE40E26C6676B003D7C48 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_OBJC_WEAK = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				INFOPLIST_FILE = CommTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 14.5;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
 				MTL_FAST_MATH = YES;
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
 				PRODUCT_BUNDLE_IDENTIFIER = swm.CommTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TARGETED_DEVICE_FAMILY = "1,2";
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Comm.app/Comm";
 				USER_HEADER_SEARCH_PATHS = (
 					../../node_modules/olm/include,
 					../../node_modules/olm/lib,
 					"${PODS_ROOT}/OLMKit/include",
 					"${PODS_ROOT}/OLMKit/lib",
 				);
 			};
 			name = Release;
 		};
 		724995DB27B4103A00323FCE /* Debug */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */;
 			buildSettings = {
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_OBJC_WEAK = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = 470;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEVELOPMENT_TEAM = H98Y8MH53M;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
 				);
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = NotificationService/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
 				INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Comm Technologies, Inc. All rights reserved.";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0.470;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				OTHER_CFLAGS = (
 					"$(inherited)",
 					"-DSQLITE_HAS_CODEC",
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-DSQLITE_TEMP_STORE=2",
 					"-DSQLCIPHER_CRYPTO_OPENSSL",
 				);
 				OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
 				PRODUCT_BUNDLE_IDENTIFIER = app.comm.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = NO;
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 1;
 			};
 			name = Debug;
 		};
 		724995DC27B4103A00323FCE /* Release */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 913E5A7BDECB327E3DE11053 /* Pods-NotificationService.release.xcconfig */;
 			buildSettings = {
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_ENABLE_OBJC_WEAK = YES;
 				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 470;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = H98Y8MH53M;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = NotificationService/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
 				INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Comm Technologies, Inc. All rights reserved.";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0.470;
 				MTL_FAST_MATH = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CFLAGS = (
 					"$(inherited)",
 					"-DSQLITE_HAS_CODEC",
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-DSQLITE_TEMP_STORE=2",
 					"-DSQLCIPHER_CRYPTO_OPENSSL",
 				);
 				OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
 				PRODUCT_BUNDLE_IDENTIFIER = app.comm.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = NO;
 				SWIFT_EMIT_LOC_STRINGS = YES;
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = 1;
 			};
 			name = Release;
 		};
 		83CBBA201A601CBA00E9B192 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"FB_SONARKIT_ENABLED=1",
 					"$(inherited)",
 					_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
 				);
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_CPLUSPLUSFLAGS = (
 					"$(OTHER_CFLAGS)",
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-fcxx-modules",
 					"-fmodules",
 				);
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-Wl",
 					"-ld_classic",
 				);
 				REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
 				SDKROOT = iphoneos;
 			};
 			name = Debug;
 		};
 		83CBBA211A601CBA00E9B192 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_CXX_LANGUAGE_STANDARD = "c++17";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_COMMA = YES;
 				CLANG_WARN_CONSTANT_CONVERSION = YES;
 				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 				CLANG_WARN_EMPTY_BODY = YES;
 				CLANG_WARN_ENUM_CONVERSION = YES;
 				CLANG_WARN_INFINITE_RECURSION = YES;
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				COPY_PHASE_STRIP = YES;
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
 				);
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				OTHER_CPLUSPLUSFLAGS = (
 					"$(OTHER_CFLAGS)",
 					"-DFOLLY_MOBILE=1",
 					"-DFOLLY_NO_CONFIG",
 					"-DFOLLY_USE_LIBCPP=1",
 					"-fcxx-modules",
 					"-fmodules",
 				);
 				OTHER_LDFLAGS = (
 					"$(inherited)",
 					"-Wl",
 					"-ld_classic",
 				);
 				REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
 				SDKROOT = iphoneos;
 				SWIFT_COMPILATION_MODE = wholemodule;
 				VALIDATE_PRODUCT = YES;
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
 		13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Comm" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				13B07F941A680F5B00A75B9A /* Debug */,
 				13B07F951A680F5B00A75B9A /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 		713EE40F26C6676B003D7C48 /* Build configuration list for PBXNativeTarget "CommTests" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				713EE40D26C6676B003D7C48 /* Debug */,
 				713EE40E26C6676B003D7C48 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 		724995DD27B4103A00323FCE /* Build configuration list for PBXNativeTarget "NotificationService" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				724995DB27B4103A00323FCE /* Debug */,
 				724995DC27B4103A00323FCE /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 		83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Comm" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				83CBBA201A601CBA00E9B192 /* Debug */,
 				83CBBA211A601CBA00E9B192 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};
 	rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
 }
diff --git a/web/shared-worker/_generated/comm_query_executor.wasm b/web/shared-worker/_generated/comm_query_executor.wasm
index 0774fc5aa..85ef09a14 100755
Binary files a/web/shared-worker/_generated/comm_query_executor.wasm and b/web/shared-worker/_generated/comm_query_executor.wasm differ