@@ -126,6 +126,11 @@ export interface RelaySnapshot {
126126 nonces_by_sender : Record < string , Record < string , number > > ;
127127}
128128
129+ export interface IdentitySnapshot {
130+ keys_by_sender : Record < string , SnapshotKeyRecord > ;
131+ nonces_by_sender : Record < string , Record < string , number > > ;
132+ }
133+
129134export interface MemoryRelayOptions {
130135 authToken ?: string ;
131136 maxMessagesPerRoom ?: number ;
@@ -150,6 +155,8 @@ export interface MemoryRelayService {
150155 fetch ( request : Request ) : Promise < Response > ;
151156 snapshot ( ) : RelaySnapshot ;
152157 restore ( snapshot : RelaySnapshot ) : void ;
158+ identitySnapshot ( ) : IdentitySnapshot ;
159+ restoreIdentity ( snapshot : IdentitySnapshot ) : void ;
153160 close ( ) : void ;
154161}
155162
@@ -1725,6 +1732,86 @@ export function createMemoryRelayService(options: MemoryRelayOptions = {}): Memo
17251732 } ;
17261733 }
17271734
1735+ function identitySnapshot ( ) : IdentitySnapshot {
1736+ const keysBySender : Record < string , SnapshotKeyRecord > = { } ;
1737+ for ( const [ sender , key ] of keyRegistry . entries ( ) ) {
1738+ keysBySender [ sender ] = {
1739+ public_key : key . publicKey ,
1740+ status : key . status ,
1741+ first_seen_at : key . firstSeenAt ,
1742+ last_seen_at : key . lastSeenAt ,
1743+ rotated_at : key . rotatedAt ,
1744+ revoked_at : key . revokedAt ,
1745+ github_username : key . githubUsername ,
1746+ github_verified_at : key . githubVerifiedAt ,
1747+ } ;
1748+ }
1749+
1750+ const noncesData : Record < string , Record < string , number > > = { } ;
1751+ for ( const [ sender , nonces ] of noncesBySender . entries ( ) ) {
1752+ const senderNonces : Record < string , number > = { } ;
1753+ for ( const [ nonce , ts ] of nonces . entries ( ) ) {
1754+ senderNonces [ nonce ] = ts ;
1755+ }
1756+ noncesData [ sender ] = senderNonces ;
1757+ }
1758+
1759+ return {
1760+ keys_by_sender : keysBySender ,
1761+ nonces_by_sender : noncesData ,
1762+ } ;
1763+ }
1764+
1765+ function restoreIdentity ( snapshotData : IdentitySnapshot ) : void {
1766+ keyRegistry . clear ( ) ;
1767+ noncesBySender . clear ( ) ;
1768+
1769+ if ( ! isObjectRecord ( snapshotData ) ) {
1770+ return ;
1771+ }
1772+
1773+ if ( isObjectRecord ( snapshotData . keys_by_sender ) ) {
1774+ for ( const [ sender , value ] of Object . entries ( snapshotData . keys_by_sender ) ) {
1775+ if ( ! isObjectRecord ( value ) ) continue ;
1776+ const publicKey = ( typeof value . public_key === 'string' ? value . public_key : '' ) . trim ( ) ;
1777+ if ( sender . trim ( ) . length === 0 || publicKey . length === 0 ) continue ;
1778+ const status : KeyStatus = value . status === 'revoked' ? 'revoked' : 'active' ;
1779+ keyRegistry . set ( sender , {
1780+ publicKey,
1781+ status,
1782+ firstSeenAt : typeof value . first_seen_at === 'number'
1783+ ? Math . trunc ( value . first_seen_at )
1784+ : 0 ,
1785+ lastSeenAt : typeof value . last_seen_at === 'number' ? Math . trunc ( value . last_seen_at ) : 0 ,
1786+ rotatedAt : typeof value . rotated_at === 'number' ? Math . trunc ( value . rotated_at ) : null ,
1787+ revokedAt : typeof value . revoked_at === 'number' ? Math . trunc ( value . revoked_at ) : null ,
1788+ githubUsername : typeof value . github_username === 'string' ? value . github_username : null ,
1789+ githubVerifiedAt : typeof value . github_verified_at === 'number'
1790+ ? Math . trunc ( value . github_verified_at )
1791+ : null ,
1792+ } ) ;
1793+ }
1794+ }
1795+
1796+ if ( isObjectRecord ( snapshotData . nonces_by_sender ) ) {
1797+ const nowSec = nowEpochSec ( ) ;
1798+ for ( const [ sender , value ] of Object . entries ( snapshotData . nonces_by_sender ) ) {
1799+ if ( ! isObjectRecord ( value ) ) continue ;
1800+ const map = new Map < string , number > ( ) ;
1801+ for ( const [ nonce , tsRaw ] of Object . entries ( value ) ) {
1802+ if ( nonce . trim ( ) . length === 0 ) continue ;
1803+ if ( typeof tsRaw !== 'number' || ! Number . isFinite ( tsRaw ) ) continue ;
1804+ const ts = Math . trunc ( tsRaw ) ;
1805+ if ( nowSec - ts > nonceTtlSec ) continue ;
1806+ map . set ( nonce , ts ) ;
1807+ }
1808+ if ( map . size > 0 ) {
1809+ noncesBySender . set ( sender , map ) ;
1810+ }
1811+ }
1812+ }
1813+ }
1814+
17281815 function restore ( snapshotData : RelaySnapshot ) : void {
17291816 rooms . clear ( ) ;
17301817 keyRegistry . clear ( ) ;
@@ -1883,6 +1970,8 @@ export function createMemoryRelayService(options: MemoryRelayOptions = {}): Memo
18831970 fetch,
18841971 snapshot,
18851972 restore,
1973+ identitySnapshot,
1974+ restoreIdentity,
18861975 close,
18871976 } ;
18881977}
0 commit comments