tracks lexicons and how many times they appeared on the jetstream

feat(client): load data in server function so we dont have weird empty gap with no data

ptr.pet a41cbdc9 452aff95

verified
Changed files
+39 -29
.tangled
workflows
client
-3
.tangled/workflows/build.yml
··· 11 - gnused 12 13 steps: 14 - - name: test server 15 - command: | 16 - cd server && cargo test 17 - name: build client 18 command: | 19 export PUBLIC_API_URL="localhost:3713"
··· 11 - gnused 12 13 steps: 14 - name: build client 15 command: | 16 export PUBLIC_API_URL="localhost:3713"
+2 -1
client/src/routes/+layout.ts
··· 1 export const prerender = true; 2 - export const ssr = false;
··· 1 export const prerender = true; 2 + export const ssr = true; 3 + export const csr = true;
+7
client/src/routes/+page.server.ts
···
··· 1 + import { fetchEvents, fetchTrackingSince } from "$lib/api"; 2 + 3 + export const load = async () => { 4 + const events = await fetchEvents(); 5 + const trackingSince = await fetchTrackingSince(); 6 + return { events, trackingSince }; 7 + };
+30 -25
client/src/routes/+page.svelte
··· 1 <script lang="ts"> 2 import { dev } from "$app/environment"; 3 - import type { EventRecord, NsidCount, SortOption } from "$lib/types"; 4 import { onMount, onDestroy } from "svelte"; 5 import { writable } from "svelte/store"; 6 import { PUBLIC_API_URL } from "$env/static/public"; ··· 15 import RefreshControl from "$lib/components/RefreshControl.svelte"; 16 import { formatTimestamp } from "$lib/format"; 17 18 - const events = writable(new Map<string, EventRecord>()); 19 const pendingUpdates = new Map<string, EventRecord>(); 20 let eventsList: NsidCount[] = $state([]); 21 let updateTimer: NodeJS.Timeout | null = null; ··· 28 })) 29 .toArray(); 30 }); 31 - let per_second = $state(0); 32 - let tracking_since = $state(0); 33 34 let all: EventRecord = $derived( 35 eventsList.reduce( ··· 76 }; 77 websocket.onmessage = async (event) => { 78 const jsonData = JSON.parse(event.data); 79 - 80 - if (jsonData.per_second > 0) { 81 - per_second = jsonData.per_second; 82 - } 83 - 84 - // Store updates in pending map if refresh rate is set 85 if (refreshRate) { 86 for (const [nsid, event] of Object.entries(jsonData.events)) { 87 pendingUpdates.set(nsid, event as EventRecord); 88 } 89 } else { 90 - // Apply updates immediately if no refresh rate 91 - events.update((map) => { 92 - for (const [nsid, event] of Object.entries( 93 - jsonData.events, 94 - )) { 95 - map.set(nsid, event as EventRecord); 96 - } 97 - return map; 98 - }); 99 } 100 }; 101 websocket.onerror = (error) => { ··· 114 error = null; 115 const data = await fetchEvents(); 116 per_second = data.per_second; 117 - events.update((map) => { 118 - for (const [nsid, event] of Object.entries(data.events)) { 119 - map.set(nsid, event); 120 - } 121 - return map; 122 - }); 123 tracking_since = (await fetchTrackingSince()).since; 124 } catch (err) { 125 error =
··· 1 <script lang="ts"> 2 import { dev } from "$app/environment"; 3 + import type { 4 + EventRecord, 5 + Events, 6 + NsidCount, 7 + Since, 8 + SortOption, 9 + } from "$lib/types"; 10 import { onMount, onDestroy } from "svelte"; 11 import { writable } from "svelte/store"; 12 import { PUBLIC_API_URL } from "$env/static/public"; ··· 21 import RefreshControl from "$lib/components/RefreshControl.svelte"; 22 import { formatTimestamp } from "$lib/format"; 23 24 + type Props = { 25 + data: { events: Events; trackingSince: Since }; 26 + }; 27 + 28 + const { data }: Props = $props(); 29 + 30 + const events = writable( 31 + new Map<string, EventRecord>(Object.entries(data.events.events)), 32 + ); 33 const pendingUpdates = new Map<string, EventRecord>(); 34 let eventsList: NsidCount[] = $state([]); 35 let updateTimer: NodeJS.Timeout | null = null; ··· 42 })) 43 .toArray(); 44 }); 45 + let per_second = $state(data.events.per_second); 46 + let tracking_since = $state(data.trackingSince.since); 47 + 48 + const applyEvents = (newEvents: Record<string, EventRecord>) => { 49 + events.update((map) => { 50 + for (const [nsid, event] of Object.entries(newEvents)) { 51 + map.set(nsid, event); 52 + } 53 + return map; 54 + }); 55 + }; 56 57 let all: EventRecord = $derived( 58 eventsList.reduce( ··· 99 }; 100 websocket.onmessage = async (event) => { 101 const jsonData = JSON.parse(event.data); 102 + per_second = jsonData.per_second; 103 if (refreshRate) { 104 for (const [nsid, event] of Object.entries(jsonData.events)) { 105 pendingUpdates.set(nsid, event as EventRecord); 106 } 107 } else { 108 + applyEvents(jsonData.events); 109 } 110 }; 111 websocket.onerror = (error) => { ··· 124 error = null; 125 const data = await fetchEvents(); 126 per_second = data.per_second; 127 + applyEvents(data.events); 128 tracking_since = (await fetchTrackingSince()).since; 129 } catch (err) { 130 error =