@@ -6,6 +6,7 @@ import type { DocHandle } from '@automerge/automerge-repo';
66import { RepoContext } from '@automerge/automerge-repo-react-hooks' ;
77import {
88 Identity ,
9+ InboxMessageStorageEntry ,
910 Inboxes ,
1011 Key ,
1112 Messages ,
@@ -58,6 +59,7 @@ export type HypergraphAppCtx = {
5859 params : Readonly < { isPublic : boolean ; authPolicy : Messages . InboxSenderAuthPolicy } > ,
5960 ) : Promise < unknown > ;
6061 getLatestAccountInboxMessages ( params : Readonly < { accountId : string ; inboxId : string } > ) : Promise < unknown > ;
62+ getOwnAccountInboxes ( ) : Promise < unknown > ;
6163 listPublicAccountInboxes ( params : Readonly < { accountId : string } > ) : Promise < unknown > ;
6264 getAccountInbox ( params : Readonly < { accountId : string ; inboxId : string } > ) : Promise < unknown > ;
6365 sendAccountInboxMessage (
@@ -67,6 +69,7 @@ export type HypergraphAppCtx = {
6769 inboxId : string ;
6870 encryptionPublicKey : string ;
6971 signaturePrivateKey : string | null ;
72+ authorAccountId : string ;
7073 } > ,
7174 ) : Promise < unknown > ;
7275 listSpaces ( ) : void ;
@@ -114,6 +117,9 @@ export const HypergraphAppContext = createContext<HypergraphAppCtx>({
114117 async createAccountInbox ( ) {
115118 throw new Error ( 'createAccountInbox is missing' ) ;
116119 } ,
120+ async getOwnAccountInboxes ( ) {
121+ throw new Error ( 'getOwnAccountInboxes is missing' ) ;
122+ } ,
117123 async getLatestAccountInboxMessages ( ) {
118124 throw new Error ( 'getLatestAccountInboxMessages is missing' ) ;
119125 } ,
@@ -448,6 +454,13 @@ export function HypergraphAppProvider({
448454 return {
449455 ...message ,
450456 plaintext : decryptedMessage ,
457+ signature : message . signature
458+ ? {
459+ hex : message . signature . hex ,
460+ recovery : message . signature . recovery ,
461+ }
462+ : null ,
463+ authorAccountId : message . authorAccountId ?? null ,
451464 } ;
452465 } ) ;
453466 // TODO filter messages checking the signatures are valid for the corresponding authorAccountId
@@ -552,6 +565,7 @@ export function HypergraphAppProvider({
552565 ) ,
553566 lastMessageClock : 0 ,
554567 messages : [ ] ,
568+ seenMessageIds : new Set < string > ( ) ,
555569 } ;
556570 store . send ( {
557571 type : 'setSpaceInbox' ,
@@ -608,9 +622,18 @@ export function HypergraphAppProvider({
608622 console . error ( 'Invalid inbox creator' , response . inbox ) ;
609623 return ;
610624 }
625+
626+ let lastMessageClock = 0 ;
627+ const messages : InboxMessageStorageEntry [ ] = [ ] ;
628+
611629 store . send ( {
612630 type : 'setAccountInbox' ,
613- inbox : response . inbox ,
631+ inbox : {
632+ ...response . inbox ,
633+ messages,
634+ lastMessageClock,
635+ seenMessageIds : new Set < string > ( ) ,
636+ } ,
614637 } ) ;
615638 break ;
616639 }
@@ -622,6 +645,109 @@ export function HypergraphAppProvider({
622645 // TODO: validate signature and decrypt message sealed box, then store it
623646 break ;
624647 }
648+ case 'account-inboxes' : {
649+ response . inboxes . map ( ( inbox ) => {
650+ store . send ( {
651+ type : 'setAccountInbox' ,
652+ inbox : {
653+ ...inbox ,
654+ messages : [ ] ,
655+ lastMessageClock : 0 ,
656+ seenMessageIds : new Set < string > ( ) ,
657+ } ,
658+ } ) ;
659+ } ) ;
660+ break ;
661+ }
662+ case 'account-inbox-messages' : {
663+ // Validate the signature of the inbox corresponds to the current account's identity
664+ if ( ! keys . signaturePrivateKey ) {
665+ console . error ( 'No signature private key found to process account inbox' ) ;
666+ return ;
667+ }
668+ const inbox = store . getSnapshot ( ) . context . accountInboxes . find ( ( i ) => i . inboxId === response . inboxId ) ;
669+ if ( ! inbox ) {
670+ console . error ( 'Inbox not found' , response . inboxId ) ;
671+ return ;
672+ }
673+
674+ let lastMessageClock = 0 ;
675+ const messages = response . messages . map ( ( message ) => {
676+ const decryptedMessage = Inboxes . decryptInboxMessage ( {
677+ ciphertext : message . ciphertext ,
678+ nonce : message . nonce ,
679+ ephemeralPublicKey : message . ephemeralPublicKey ,
680+ encryptionPrivateKey,
681+ } ) ;
682+ if ( message . createdAt > lastMessageClock ) {
683+ lastMessageClock = message . createdAt ;
684+ }
685+ return {
686+ ...message ,
687+ plaintext : decryptedMessage ,
688+ signature : message . signature
689+ ? {
690+ hex : message . signature . hex ,
691+ recovery : message . signature . recovery ,
692+ }
693+ : null ,
694+ authorAccountId : message . authorAccountId ?? null ,
695+ } ;
696+ } ) ;
697+
698+ store . send ( {
699+ type : 'setAccountInboxMessages' ,
700+ inboxId : response . inboxId ,
701+ messages,
702+ lastMessageClock,
703+ } ) ;
704+ break ;
705+ }
706+ case 'space-inbox-messages' : {
707+ const space = store . getSnapshot ( ) . context . spaces . find ( ( s ) => s . id === response . spaceId ) ;
708+ if ( ! space ) {
709+ console . error ( 'Space not found' , response . spaceId ) ;
710+ return ;
711+ }
712+ const inbox = space . inboxes . find ( ( i ) => i . inboxId === response . inboxId ) ;
713+ if ( ! inbox ) {
714+ console . error ( 'Inbox not found' , response . inboxId ) ;
715+ return ;
716+ }
717+
718+ let lastMessageClock = 0 ;
719+ const messages = response . messages . map ( ( message ) => {
720+ const decryptedMessage = Inboxes . decryptInboxMessage ( {
721+ ciphertext : message . ciphertext ,
722+ nonce : message . nonce ,
723+ ephemeralPublicKey : message . ephemeralPublicKey ,
724+ encryptionPrivateKey,
725+ } ) ;
726+ if ( message . createdAt > lastMessageClock ) {
727+ lastMessageClock = message . createdAt ;
728+ }
729+ return {
730+ ...message ,
731+ signature : message . signature
732+ ? {
733+ hex : message . signature . hex ,
734+ recovery : message . signature . recovery ,
735+ }
736+ : null ,
737+ authorAccountId : message . authorAccountId ?? null ,
738+ plaintext : decryptedMessage ,
739+ } ;
740+ } ) ;
741+
742+ store . send ( {
743+ type : 'setSpaceInboxMessages' ,
744+ spaceId : response . spaceId ,
745+ inboxId : response . inboxId ,
746+ messages,
747+ lastMessageClock,
748+ } ) ;
749+ break ;
750+ }
625751 default : {
626752 Utils . assertExhaustive ( response ) ;
627753 }
@@ -759,7 +885,7 @@ export function HypergraphAppProvider({
759885 console . error ( 'Space not found' , spaceId ) ;
760886 return ;
761887 }
762- const inbox = space . inboxes . find ( ( i ) => i . id === inboxId ) ;
888+ const inbox = space . inboxes . find ( ( i ) => i . inboxId === inboxId ) ;
763889 if ( ! inbox ) {
764890 console . error ( 'Inbox not found' , inboxId ) ;
765891 return ;
@@ -790,6 +916,35 @@ export function HypergraphAppProvider({
790916 [ syncServerUri ] ,
791917 ) ;
792918
919+ const sendSpaceInboxMessageForContext = useCallback (
920+ async ( {
921+ spaceId,
922+ inboxId,
923+ message,
924+ encryptionPublicKey,
925+ signaturePrivateKey,
926+ authorAccountId,
927+ } : Readonly < {
928+ spaceId : string ;
929+ inboxId : string ;
930+ message : string ;
931+ encryptionPublicKey : string ;
932+ signaturePrivateKey : string ;
933+ authorAccountId : string ;
934+ } > ) => {
935+ return await Inboxes . sendSpaceInboxMessage ( {
936+ spaceId,
937+ inboxId,
938+ message,
939+ encryptionPublicKey,
940+ signaturePrivateKey,
941+ syncServerUri,
942+ authorAccountId,
943+ } ) ;
944+ } ,
945+ [ syncServerUri ] ,
946+ ) ;
947+
793948 const createAccountInboxForContext = useCallback (
794949 async ( { isPublic, authPolicy } : Readonly < { isPublic : boolean ; authPolicy : Messages . InboxSenderAuthPolicy } > ) => {
795950 if ( ! accountId ) {
@@ -833,6 +988,13 @@ export function HypergraphAppProvider({
833988 [ websocketConnection ] ,
834989 ) ;
835990
991+ const getOwnAccountInboxesForContext = useCallback ( async ( ) => {
992+ const message : Messages . RequestGetAccountInboxes = {
993+ type : 'get-account-inboxes' ,
994+ } ;
995+ websocketConnection ?. send ( Messages . serialize ( message ) ) ;
996+ } , [ websocketConnection ] ) ;
997+
836998 const listPublicAccountInboxesForContext = useCallback (
837999 async ( { accountId } : Readonly < { accountId : string } > ) => {
8381000 return await Inboxes . listPublicAccountInboxes ( { accountId, syncServerUri } ) ;
@@ -847,6 +1009,35 @@ export function HypergraphAppProvider({
8471009 [ syncServerUri ] ,
8481010 ) ;
8491011
1012+ const sendAccountInboxMessageForContext = useCallback (
1013+ async ( {
1014+ message,
1015+ accountId,
1016+ inboxId,
1017+ encryptionPublicKey,
1018+ signaturePrivateKey,
1019+ authorAccountId,
1020+ } : Readonly < {
1021+ message : string ;
1022+ accountId : string ;
1023+ inboxId : string ;
1024+ encryptionPublicKey : string ;
1025+ signaturePrivateKey : string | null ;
1026+ authorAccountId : string ;
1027+ } > ) => {
1028+ return await Inboxes . sendAccountInboxMessage ( {
1029+ message,
1030+ accountId,
1031+ inboxId,
1032+ encryptionPublicKey,
1033+ signaturePrivateKey,
1034+ syncServerUri,
1035+ authorAccountId,
1036+ } ) ;
1037+ } ,
1038+ [ syncServerUri ] ,
1039+ ) ;
1040+
8501041 const acceptInvitationForContext = useCallback (
8511042 async ( {
8521043 invitation,
@@ -1007,6 +1198,7 @@ export function HypergraphAppProvider({
10071198 sendSpaceInboxMessage : sendSpaceInboxMessageForContext ,
10081199 createAccountInbox : createAccountInboxForContext ,
10091200 getLatestAccountInboxMessages : getLatestAccountInboxMessagesForContext ,
1201+ getOwnAccountInboxes : getOwnAccountInboxesForContext ,
10101202 listPublicAccountInboxes : listPublicAccountInboxesForContext ,
10111203 getAccountInbox : getAccountInboxForContext ,
10121204 sendAccountInboxMessage : sendAccountInboxMessageForContext ,
0 commit comments