notification manager for bsky
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

swap typeahead to typeahead.waow.tech

Drop-in compatible with app.bsky.actor.searchActorsTypeahead; public endpoint,
no auth. Removes a createAgent() call from every @-typeahead keystroke, which
was burning the Bluesky 10/day login rate limit during iteration. Overridable
via TYPEAHEAD_URL if the community service is down.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

zzstoatzz 582a1dc2 2941d199

+28 -5
+27 -3
src/bluesky.ts
··· 147 147 return out 148 148 } 149 149 150 + const TYPEAHEAD_URL = process.env.TYPEAHEAD_URL || 'https://typeahead.waow.tech' 151 + 152 + type TypeaheadActor = { 153 + did: string 154 + handle: string 155 + displayName?: string 156 + avatar?: string 157 + } 158 + 159 + // Community-run actor search (https://typeahead.waow.tech) — drop-in compatible 160 + // with app.bsky.actor.searchActorsTypeahead. Public endpoint, no auth required, 161 + // so this no longer burns login-session budget on every keystroke. 150 162 export async function searchActorSuggestions( 151 - agent: AtpAgent, 152 163 query: string, 153 164 limit = 6, 154 165 ): Promise<ActorRef[]> { 155 166 const trimmed = query.trim().replace(/^@/, '') 156 167 if (!trimmed) return [] 157 - const res = await agent.searchActorsTypeahead({q: trimmed, limit}) 158 - return res.data.actors.map(actorRefFromProfile) 168 + const url = `${TYPEAHEAD_URL}/xrpc/app.bsky.actor.searchActorsTypeahead?q=${encodeURIComponent(trimmed)}&limit=${limit}` 169 + try { 170 + const res = await fetch(url, {headers: {'X-Client': 'noti'}}) 171 + if (!res.ok) return [] 172 + const body = (await res.json()) as {actors?: TypeaheadActor[]} 173 + const actors = Array.isArray(body.actors) ? body.actors : [] 174 + return actors.map(actor => ({ 175 + did: actor.did, 176 + handle: actor.handle, 177 + name: actor.displayName || actor.handle, 178 + profileUrl: actorProfileUrl(actor.handle), 179 + })) 180 + } catch { 181 + return [] 182 + } 159 183 } 160 184 161 185 export async function listActivitySubscriptions(agent: AtpAgent) {
+1 -2
src/server.ts
··· 583 583 const local = localActorSuggestions(base, q, 8) 584 584 const merged = new Map(local.map(actor => [actor.did, actor])) 585 585 if (q) { 586 - const agent = await createAgent() 587 - const remote = await searchActorSuggestions(agent, q, 8) 586 + const remote = await searchActorSuggestions(q, 8) 588 587 for (const actor of remote) { 589 588 if (!merged.has(actor.did)) { 590 589 merged.set(actor.did, actor)