@@ -27,6 +27,9 @@ import {
2727 trackMessageSent ,
2828 trackMessageReceived ,
2929 recordLatency ,
30+ updateStoreQueryStatus ,
31+ displayStoreQueryResults ,
32+ clearStoreQueryResults ,
3033} from "./ui-manager" ;
3134
3235const NUM_MESSAGES_PER_BATCH = 5 ;
@@ -206,6 +209,100 @@ async function initializeApp() {
206209 console . log ( "Subscription active." ) ;
207210 } ;
208211
212+ const queryStoreMessages = async ( ) => {
213+ const storeMessageCountInput = document . getElementById ( "storeMessageCount" ) as HTMLInputElement ;
214+ const messageLimit = storeMessageCountInput ? parseInt ( storeMessageCountInput . value , 10 ) : 5 ;
215+
216+ if ( isNaN ( messageLimit ) || messageLimit < 1 ) {
217+ updateStoreQueryStatus ( "Please enter a valid number of messages (minimum 1)" , true ) ;
218+ return ;
219+ }
220+
221+ clearStoreQueryResults ( ) ;
222+ updateStoreQueryStatus ( "Querying store..." , false ) ;
223+ console . log ( `Querying store for up to ${ messageLimit } messages...` ) ;
224+
225+ try {
226+ const decoder = createWakuDecoder ( ) ;
227+ const allMessages : ChatMessage [ ] = [ ] ;
228+
229+ console . log ( "Decoder content topic:" , decoder . contentTopic ) ;
230+ console . log ( "Decoder pubsub topic:" , decoder . pubsubTopic ) ;
231+
232+ // Query for messages from the last hour, using paginationLimit to control result size
233+ const timeEnd = new Date ( ) ;
234+ const timeStart = new Date ( Date . now ( ) - 1000 * 60 * 60 ) ;
235+
236+ const queryOptions = {
237+ timeStart,
238+ timeEnd,
239+ paginationForward : false , // Start from newest
240+ paginationLimit : messageLimit , // Limit the number of messages returned
241+ } ;
242+
243+ console . log ( "Store query options:" , queryOptions ) ;
244+ console . log ( "Time range:" , timeStart . toISOString ( ) , "to" , timeEnd . toISOString ( ) ) ;
245+
246+ // Collect messages - stop once we have enough
247+ await node . store . queryWithOrderedCallback (
248+ [ decoder ] ,
249+ async ( wakuMessage ) => {
250+ // Check if we already have enough messages before processing more
251+ if ( allMessages . length >= messageLimit ) {
252+ console . log ( `Already collected ${ messageLimit } messages, stopping` ) ;
253+ return true ; // Stop processing
254+ }
255+
256+ const chatMessage = decodeMessage ( wakuMessage . payload ) ;
257+ if ( chatMessage ) {
258+ allMessages . push ( chatMessage ) ;
259+ console . log ( `Store found message ${ allMessages . length } /${ messageLimit } :` , {
260+ id : chatMessage . id ,
261+ content : chatMessage . content . substring ( 0 , 50 ) ,
262+ timestamp : new Date ( chatMessage . timestamp ) . toISOString ( ) ,
263+ sender : chatMessage . senderPeerId . substring ( 0 , 12 )
264+ } ) ;
265+
266+ // Stop if we've reached the limit
267+ if ( allMessages . length >= messageLimit ) {
268+ console . log ( `Reached limit of ${ messageLimit } messages, stopping` ) ;
269+ return true ; // Stop processing
270+ }
271+ } else {
272+ console . warn ( "Failed to decode message from store" ) ;
273+ }
274+
275+ return false ; // Continue to next message
276+ } ,
277+ queryOptions
278+ ) ;
279+
280+ console . log ( `Store query completed. Collected ${ allMessages . length } messages.` ) ;
281+
282+ if ( allMessages . length > 0 ) {
283+ // Sort by timestamp descending (newest first)
284+ // Since we're querying with paginationForward: false, we're getting recent messages,
285+ // but they may not be in perfect order, so we sort them
286+ allMessages . sort ( ( a , b ) => b . timestamp - a . timestamp ) ;
287+
288+ console . log ( `Returning ${ allMessages . length } message(s)` ) ;
289+ console . log ( "Newest message timestamp:" , new Date ( allMessages [ 0 ] . timestamp ) . toISOString ( ) ) ;
290+ if ( allMessages . length > 1 ) {
291+ console . log ( "Oldest returned message timestamp:" , new Date ( allMessages [ allMessages . length - 1 ] . timestamp ) . toISOString ( ) ) ;
292+ }
293+
294+ updateStoreQueryStatus ( `✓ Successfully retrieved ${ allMessages . length } message${ allMessages . length !== 1 ? 's' : '' } from store` , false ) ;
295+ displayStoreQueryResults ( allMessages ) ;
296+ } else {
297+ updateStoreQueryStatus ( "✓ Query completed successfully, but no messages found in store" , false ) ;
298+ displayStoreQueryResults ( [ ] ) ;
299+ }
300+ } catch ( error ) {
301+ console . error ( "Error querying store:" , error ) ;
302+ updateStoreQueryStatus ( `✗ Error querying store: ${ error instanceof Error ? error . message : String ( error ) } ` , true ) ;
303+ }
304+ } ;
305+
209306 const sendMessageButton = document . getElementById ( "sendMessageButton" ) ;
210307 if ( sendMessageButton ) {
211308 sendMessageButton . addEventListener ( "click" , ( ) => {
@@ -241,6 +338,14 @@ async function initializeApp() {
241338 } ) ;
242339 }
243340
341+ const queryStoreButton = document . getElementById ( "queryStoreButton" ) ;
342+ if ( queryStoreButton ) {
343+ queryStoreButton . addEventListener ( "click" , ( ) => {
344+ console . log ( "Query Store button clicked" ) ;
345+ queryStoreMessages ( ) ;
346+ } ) ;
347+ }
348+
244349 initCharts ( ) ;
245350 ( window as any ) . onDiscoveryUpdate = onDiscoveryUpdate ;
246351 ( window as any ) . onConnectionsUpdate = onConnectionsUpdate ;
0 commit comments