managed-outbox.service.ts raw
1 import { normalizeUrl } from '@/lib/url'
2 import relayStatsService from './relay-stats.service'
3 import storage from './local-storage.service'
4 import type { TRelayDirection, TOutboxMode, TRelayEntry } from '@/types/relay-management'
5
6 class ManagedOutboxService {
7 filterRelayUrls(
8 urls: string[],
9 direction: TRelayDirection,
10 ownRelays?: Set<string>
11 ): string[] {
12 const mode = storage.getOutboxMode() as TOutboxMode
13 const normalizedOwn = ownRelays ? new Set([...ownRelays].map(normalizeUrl)) : undefined
14 const allowed: string[] = []
15
16 for (let url of urls) {
17 url = normalizeUrl(url)
18 if (normalizedOwn?.has(url)) {
19 allowed.push(url)
20 continue
21 }
22
23 const entry = relayStatsService.getEntry(url)
24
25 if (entry?.manualExclude) continue
26 if (relayStatsService.isAutoDisabled(url)) continue
27
28 if (mode === 'automatic') {
29 if (!entry) {
30 this.addPending(url, direction)
31 }
32 allowed.push(url)
33 continue
34 }
35
36 // mode === 'managed'
37 if (entry?.status === 'approved') {
38 allowed.push(url)
39 } else if (entry?.status === 'rejected') {
40 // blocked
41 } else {
42 // pending or no entry
43 this.addPending(url, direction)
44 }
45 }
46
47 return allowed
48 }
49
50 addPending(url: string, direction: TRelayDirection, reason?: string): void {
51 const existing = relayStatsService.getEntry(url)
52 if (!existing) {
53 const entry = relayStatsService.getOrCreateEntry(url)
54 entry.direction = direction
55 if (reason) entry.reason = reason
56 // status defaults to 'pending' from getOrCreateEntry
57 return
58 }
59 if (existing.direction !== direction && existing.direction !== 'both') {
60 relayStatsService.updateEntry(url, { direction: 'both' })
61 }
62 if (reason && !existing.reason) {
63 relayStatsService.updateEntry(url, { reason })
64 }
65 }
66
67 approve(url: string): void {
68 relayStatsService.updateEntry(url, { status: 'approved' })
69 }
70
71 reject(url: string): void {
72 relayStatsService.updateEntry(url, { status: 'rejected' })
73 }
74
75 resetStatus(url: string): void {
76 relayStatsService.updateEntry(url, { status: 'pending' })
77 }
78
79 setManualExclude(url: string, excluded: boolean): void {
80 relayStatsService.updateEntry(url, { manualExclude: excluded })
81 }
82
83 bulkApprove(urls: string[]): void {
84 for (const url of urls) this.approve(url)
85 }
86
87 bulkReject(urls: string[]): void {
88 for (const url of urls) this.reject(url)
89 }
90
91 getPendingRelays(): TRelayEntry[] {
92 return relayStatsService.getAllEntries().filter((e) => e.status === 'pending')
93 }
94
95 getApprovedRelays(): TRelayEntry[] {
96 return relayStatsService.getAllEntries().filter((e) => e.status === 'approved')
97 }
98
99 getRejectedRelays(): TRelayEntry[] {
100 return relayStatsService.getAllEntries().filter((e) => e.status === 'rejected')
101 }
102
103 getExcludedRelays(): TRelayEntry[] {
104 return relayStatsService.getAllEntries().filter((e) => e.manualExclude)
105 }
106
107 getAutoDisabledRelays(): TRelayEntry[] {
108 return relayStatsService
109 .getAllEntries()
110 .filter((e) => relayStatsService.isAutoDisabled(e.url))
111 }
112 }
113
114 const managedOutboxService = new ManagedOutboxService()
115 export default managedOutboxService
116