Sifa professional network API (Fastify, AT Protocol, Jetstream)
sifa.id/
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});