about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/api/search.ts69
-rw-r--r--src/lib/routes/router.ts29
-rw-r--r--src/lib/routes/types.ts6
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
 }