Sifa professional network API (Fastify, AT Protocol, Jetstream) sifa.id/
at main 198 lines 5.2 kB view raw
1import { describe, it, expect, vi } from 'vitest'; 2import { createEventRouter } from '../../src/jetstream/handler.js'; 3 4// Mock db — identity events upsert into profiles table, child indexers ensure profile row 5const mockDb = { 6 insert: vi.fn().mockReturnValue({ 7 values: vi.fn().mockReturnValue({ 8 onConflictDoUpdate: vi.fn(), 9 onConflictDoNothing: vi.fn(), 10 }), 11 }), 12} as unknown as Parameters<typeof createEventRouter>[0]; 13 14describe('Event router', () => { 15 it('routes profile.self events to profile indexer', async () => { 16 const profileIndexer = vi.fn(); 17 const router = createEventRouter(mockDb, { profileIndexer }); 18 19 await router({ 20 did: 'did:plc:test', 21 time_us: 1234567890, 22 kind: 'commit', 23 commit: { 24 rev: 'rev1', 25 operation: 'create', 26 collection: 'id.sifa.profile.self', 27 rkey: 'self', 28 record: { headline: 'Test', createdAt: '2026-01-01T00:00:00Z' }, 29 }, 30 }); 31 32 expect(profileIndexer).toHaveBeenCalledOnce(); 33 }); 34 35 it('ignores unknown collections', async () => { 36 const profileIndexer = vi.fn(); 37 const router = createEventRouter(mockDb, { profileIndexer }); 38 39 await router({ 40 did: 'did:plc:test', 41 time_us: 1234567890, 42 kind: 'commit', 43 commit: { 44 rev: 'rev1', 45 operation: 'create', 46 collection: 'app.bsky.feed.post', 47 rkey: '123', 48 record: {}, 49 }, 50 }); 51 52 expect(profileIndexer).not.toHaveBeenCalled(); 53 }); 54 55 it('routes position events to position indexer', async () => { 56 const positionIndexer = vi.fn(); 57 const router = createEventRouter(mockDb, { positionIndexer }); 58 59 await router({ 60 did: 'did:plc:test', 61 time_us: 1234567890, 62 kind: 'commit', 63 commit: { 64 rev: 'rev1', 65 operation: 'create', 66 collection: 'id.sifa.profile.position', 67 rkey: '3abc', 68 record: { companyName: 'Acme', title: 'Eng' }, 69 }, 70 }); 71 72 expect(positionIndexer).toHaveBeenCalledOnce(); 73 }); 74 75 it('routes education events to education indexer', async () => { 76 const educationIndexer = vi.fn(); 77 const router = createEventRouter(mockDb, { educationIndexer }); 78 79 await router({ 80 did: 'did:plc:test', 81 time_us: 1234567890, 82 kind: 'commit', 83 commit: { 84 rev: 'rev1', 85 operation: 'create', 86 collection: 'id.sifa.profile.education', 87 rkey: '3abc', 88 record: { institution: 'MIT', degree: 'BS' }, 89 }, 90 }); 91 92 expect(educationIndexer).toHaveBeenCalledOnce(); 93 }); 94 95 it('routes skill events to skill indexer', async () => { 96 const skillIndexer = vi.fn(); 97 const router = createEventRouter(mockDb, { skillIndexer }); 98 99 await router({ 100 did: 'did:plc:test', 101 time_us: 1234567890, 102 kind: 'commit', 103 commit: { 104 rev: 'rev1', 105 operation: 'create', 106 collection: 'id.sifa.profile.skill', 107 rkey: '3abc', 108 record: { skillName: 'TypeScript', category: 'Programming' }, 109 }, 110 }); 111 112 expect(skillIndexer).toHaveBeenCalledOnce(); 113 }); 114 115 it('routes follow events to follow indexer', async () => { 116 const followIndexer = vi.fn(); 117 const router = createEventRouter(mockDb, { followIndexer }); 118 119 await router({ 120 did: 'did:plc:test', 121 time_us: 1234567890, 122 kind: 'commit', 123 commit: { 124 rev: 'rev1', 125 operation: 'create', 126 collection: 'id.sifa.graph.follow', 127 rkey: '3abc', 128 record: { subject: 'did:plc:other' }, 129 }, 130 }); 131 132 expect(followIndexer).toHaveBeenCalledOnce(); 133 }); 134 135 it('handles identity events by updating handle', async () => { 136 const profileIndexer = vi.fn(); 137 const db = { 138 insert: vi.fn().mockReturnValue({ 139 values: vi.fn().mockReturnValue({ 140 onConflictDoUpdate: vi.fn(), 141 }), 142 }), 143 } as unknown as Parameters<typeof createEventRouter>[0]; 144 145 const router = createEventRouter(db, { profileIndexer }); 146 147 await router({ 148 did: 'did:plc:test', 149 time_us: 1234567890, 150 kind: 'identity', 151 identity: { 152 did: 'did:plc:test', 153 handle: 'test.bsky.social', 154 }, 155 }); 156 157 expect(profileIndexer).not.toHaveBeenCalled(); 158 expect(db.insert).toHaveBeenCalled(); 159 }); 160 161 it('ignores account events', async () => { 162 const profileIndexer = vi.fn(); 163 const router = createEventRouter(mockDb, { profileIndexer }); 164 165 await router({ 166 did: 'did:plc:test', 167 time_us: 1234567890, 168 kind: 'account', 169 account: { 170 active: true, 171 }, 172 }); 173 174 expect(profileIndexer).not.toHaveBeenCalled(); 175 }); 176 177 it('passes full event to indexer', async () => { 178 const profileIndexer = vi.fn(); 179 const router = createEventRouter(mockDb, { profileIndexer }); 180 181 const event = { 182 did: 'did:plc:test', 183 time_us: 1234567890, 184 kind: 'commit' as const, 185 commit: { 186 rev: 'rev1', 187 operation: 'create' as const, 188 collection: 'id.sifa.profile.self', 189 rkey: 'self', 190 record: { headline: 'Test', createdAt: '2026-01-01T00:00:00Z' }, 191 }, 192 }; 193 194 await router(event); 195 196 expect(profileIndexer).toHaveBeenCalledWith(event); 197 }); 198});