๐ src/web3/vue/composables/useSubscriptionSync.ts
D-OPEN SOVEREIGN
Documentation & Insights
Read-only reactive wrapper over subscription-sync state for one userId
(spec ยง15.8 / ยง14.11). It does NOT trigger a sync and does NOT touch
patches โ syncAccount() (session/sync.ts) is the only trigger, on the
post-write and boot/discovery paths (ยง4.6), and it already decodes,
persists, and merges any newly-delivered patches into the ORM internally.
This composable only surfaces whatever cursorStore currently holds plus an
applied-patch count from WalletEvents.emitSubscriptionPatchesSynced, for
UX (toast/badge) use โ the same relationship useWeb3Session() has to
sessionStore.1import { onScopeDispose, ref, type Ref } from 'vue';
2import { WalletEvents } from '../../events/wallet_events';
3import { cursorStore } from '../../subscription/sync-cursor';
4import type { SyncCursor } from '../../subscription/types';
5
6export interface UseSubscriptionSyncReturn {
7 cursor: Ref<SyncCursor | null>;
8 appliedCount: Ref<number>;
9 isLoading: Ref<boolean>;
10 refresh(): Promise<void>;
11}
12
13/**
14 * Read-only reactive wrapper over subscription-sync state for one userId
15 * (spec ยง15.8 / ยง14.11). It does NOT trigger a sync and does NOT touch
16 * patches โ syncAccount() (session/sync.ts) is the only trigger, on the
17 * post-write and boot/discovery paths (ยง4.6), and it already decodes,
18 * persists, and merges any newly-delivered patches into the ORM internally.
19 * This composable only surfaces whatever cursorStore currently holds plus an
20 * applied-patch count from WalletEvents.emitSubscriptionPatchesSynced, for
21 * UX (toast/badge) use โ the same relationship useWeb3Session() has to
22 * sessionStore.
23 */
24export function useSubscriptionSync(userId: number): UseSubscriptionSyncReturn {
25 const cursor = ref<SyncCursor | null>(null) as Ref<SyncCursor | null>;
26 const appliedCount = ref(0);
27 const isLoading = ref(false);
28
29 async function refresh(): Promise<void> {
30 isLoading.value = true;
31 try {
32 cursor.value = (await cursorStore.get(userId)) ?? null;
33 } finally {
34 isLoading.value = false;
35 }
36 }
37
38 refresh();
39
40 const unsubscribe = WalletEvents.onSubscriptionPatchesSynced((event) => {
41 if (event.rootUserId !== userId) return;
42 appliedCount.value = event.appliedCount;
43 void refresh(); // pick up the cursor advance that shipped with this batch
44 });
45
46 onScopeDispose(unsubscribe);
47
48 return { cursor, appliedCount, isLoading, refresh };
49}
50