diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/api/search.ts | 69 | ||||
-rw-r--r-- | src/lib/routes/router.ts | 29 | ||||
-rw-r--r-- | src/lib/routes/types.ts | 6 |
3 files changed, 94 insertions, 10 deletions
diff --git a/src/lib/api/search.ts b/src/lib/api/search.ts new file mode 100644 index 000000000..dfe9b688b --- /dev/null +++ b/src/lib/api/search.ts @@ -0,0 +1,69 @@ +/** + * This is a temporary off-spec search endpoint + * TODO removeme when we land this in proto! + */ +import {AppBskyFeedPost} from '@atproto/api' + +const PROFILES_ENDPOINT = 'https://search.bsky.social/search/profiles' +const POSTS_ENDPOINT = 'https://search.bsky.social/search/posts' + +export interface ProfileSearchItem { + $type: string + avatar: { + cid: string + mimeType: string + } + banner: { + cid: string + mimeType: string + } + description: string | undefined + displayName: string | undefined + did: string +} + +export interface PostSearchItem { + tid: string + cid: string + user: { + did: string + handle: string + } + post: AppBskyFeedPost.Record +} + +export async function searchProfiles( + query: string, +): Promise<ProfileSearchItem[]> { + return await doFetch<ProfileSearchItem[]>(PROFILES_ENDPOINT, query) +} + +export async function searchPosts(query: string): Promise<PostSearchItem[]> { + return await doFetch<PostSearchItem[]>(POSTS_ENDPOINT, query) +} + +async function doFetch<T>(endpoint: string, query: string): Promise<T> { + const controller = new AbortController() + const to = setTimeout(() => controller.abort(), 15e3) + + const uri = new URL(endpoint) + uri.searchParams.set('q', query) + + const res = await fetch(String(uri), { + method: 'get', + headers: { + accept: 'application/json', + }, + signal: controller.signal, + }) + + const resHeaders: Record<string, string> = {} + res.headers.forEach((value: string, key: string) => { + resHeaders[key] = value + }) + let resBody = await res.json() + + clearTimeout(to) + + return resBody as unknown as T +} diff --git a/src/lib/routes/router.ts b/src/lib/routes/router.ts index 05e0a63de..00defaeda 100644 --- a/src/lib/routes/router.ts +++ b/src/lib/routes/router.ts @@ -32,24 +32,39 @@ export class Router { } function createRoute(pattern: string): Route { - let matcherReInternal = pattern.replace( - /:([\w]+)/g, - (_m, name) => `(?<${name}>[^/]+)`, - ) + const pathParamNames: Set<string> = new Set() + let matcherReInternal = pattern.replace(/:([\w]+)/g, (_m, name) => { + pathParamNames.add(name) + return `(?<${name}>[^/]+)` + }) const matcherRe = new RegExp(`^${matcherReInternal}([?]|$)`, 'i') return { match(path: string) { - const res = matcherRe.exec(path) + const {pathname, searchParams} = new URL(path, 'http://throwaway.com') + const addedParams = Object.fromEntries(searchParams.entries()) + + const res = matcherRe.exec(pathname) if (res) { - return {params: res.groups || {}} + return {params: Object.assign(addedParams, res.groups || {})} } return undefined }, build(params: Record<string, string>) { - return pattern.replace( + const str = pattern.replace( /:([\w]+)/g, (_m, name) => params[name] || 'undefined', ) + + let hasQp = false + const qp = new URLSearchParams() + for (const paramName in params) { + if (!pathParamNames.has(paramName)) { + qp.set(paramName, params[paramName]) + hasQp = true + } + } + + return str + (hasQp ? `?${qp.toString()}` : '') }, } } diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts index 9ec623970..cc48e2dbe 100644 --- a/src/lib/routes/types.ts +++ b/src/lib/routes/types.ts @@ -23,7 +23,7 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & { } export type SearchTabNavigatorParams = CommonNavigatorParams & { - Search: undefined + Search: {q?: string} } export type NotificationsTabNavigatorParams = CommonNavigatorParams & { @@ -32,7 +32,7 @@ export type NotificationsTabNavigatorParams = CommonNavigatorParams & { export type FlatNavigatorParams = CommonNavigatorParams & { Home: undefined - Search: undefined + Search: {q?: string} Notifications: undefined } @@ -40,7 +40,7 @@ export type AllNavigatorParams = CommonNavigatorParams & { HomeTab: undefined Home: undefined SearchTab: undefined - Search: undefined + Search: {q?: string} NotificationsTab: undefined Notifications: undefined } |