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/analytics/analytics.tsx18
-rw-r--r--src/lib/api/index.ts28
-rw-r--r--src/lib/async/revertible.ts68
-rw-r--r--src/lib/link-meta/bsky.ts13
-rw-r--r--src/lib/link-meta/link-meta.ts12
-rw-r--r--src/lib/media/image-sizes.ts34
-rw-r--r--src/lib/strings/url-helpers.ts2
7 files changed, 62 insertions, 113 deletions
diff --git a/src/lib/analytics/analytics.tsx b/src/lib/analytics/analytics.tsx
index 4b955b365..3a8254eb1 100644
--- a/src/lib/analytics/analytics.tsx
+++ b/src/lib/analytics/analytics.tsx
@@ -7,13 +7,21 @@ import {
   useAnalytics as useAnalyticsOrig,
   ClientMethods,
 } from '@segment/analytics-react-native'
-import {AppInfo} from 'state/models/root-store'
+import {z} from 'zod'
 import {useSession} from '#/state/session'
 import {sha256} from 'js-sha256'
 import {ScreenEvent, TrackEvent} from './types'
 import {logger} from '#/logger'
 import {listenSessionLoaded} from '#/state/events'
 
+export const appInfo = z.object({
+  build: z.string().optional(),
+  name: z.string().optional(),
+  namespace: z.string().optional(),
+  version: z.string().optional(),
+})
+export type AppInfo = z.infer<typeof appInfo>
+
 const segmentClient = createClient({
   writeKey: '8I6DsgfiSLuoONyaunGoiQM7A6y2ybdI',
   trackAppLifecycleEvents: false,
@@ -128,7 +136,11 @@ async function writeAppInfo(value: AppInfo) {
   await AsyncStorage.setItem('BSKY_APP_INFO', JSON.stringify(value))
 }
 
-async function readAppInfo(): Promise<Partial<AppInfo> | undefined> {
+async function readAppInfo(): Promise<AppInfo | undefined> {
   const rawData = await AsyncStorage.getItem('BSKY_APP_INFO')
-  return rawData ? JSON.parse(rawData) : undefined
+  const obj = rawData ? JSON.parse(rawData) : undefined
+  if (!obj || typeof obj !== 'object') {
+    return undefined
+  }
+  return obj
 }
diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts
index 92620c459..a78abcacd 100644
--- a/src/lib/api/index.ts
+++ b/src/lib/api/index.ts
@@ -10,7 +10,6 @@ import {
   RichText,
 } from '@atproto/api'
 import {AtUri} from '@atproto/api'
-import {RootStoreModel} from 'state/models/root-store'
 import {isNetworkError} from 'lib/strings/errors'
 import {LinkMeta} from '../link-meta/link-meta'
 import {isWeb} from 'platform/detection'
@@ -26,33 +25,6 @@ export interface ExternalEmbedDraft {
   localThumb?: ImageModel
 }
 
-export async function resolveName(store: RootStoreModel, didOrHandle: string) {
-  if (!didOrHandle) {
-    throw new Error('Invalid handle: ""')
-  }
-  if (didOrHandle.startsWith('did:')) {
-    return didOrHandle
-  }
-
-  // we run the resolution always to ensure freshness
-  const promise = store.agent
-    .resolveHandle({
-      handle: didOrHandle,
-    })
-    .then(res => {
-      store.handleResolutions.cache.set(didOrHandle, res.data.did)
-      return res.data.did
-    })
-
-  // but we can return immediately if it's cached
-  const cached = store.handleResolutions.cache.get(didOrHandle)
-  if (cached) {
-    return cached
-  }
-
-  return promise
-}
-
 export async function uploadBlob(
   agent: BskyAgent,
   blob: string,
diff --git a/src/lib/async/revertible.ts b/src/lib/async/revertible.ts
deleted file mode 100644
index 43383b61e..000000000
--- a/src/lib/async/revertible.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import {runInAction} from 'mobx'
-import {deepObserve} from 'mobx-utils'
-import set from 'lodash.set'
-
-const ongoingActions = new Set<any>()
-
-/**
- * This is a TypeScript function that optimistically updates data on the client-side before sending a
- * request to the server and rolling back changes if the request fails.
- * @param {T} model - The object or record that needs to be updated optimistically.
- * @param preUpdate - `preUpdate` is a function that is called before the server update is executed. It
- * can be used to perform any necessary actions or updates on the model or UI before the server update
- * is initiated.
- * @param serverUpdate - `serverUpdate` is a function that returns a Promise representing the server
- * update operation. This function is called after the previous state of the model has been recorded
- * and the `preUpdate` function has been executed. If the server update is successful, the `postUpdate`
- * function is called with the result
- * @param [postUpdate] - `postUpdate` is an optional callback function that will be called after the
- * server update is successful. It takes in the response from the server update as its parameter. If
- * this parameter is not provided, nothing will happen after the server update.
- * @returns A Promise that resolves to `void`.
- */
-export const updateDataOptimistically = async <
-  T extends Record<string, any>,
-  U,
->(
-  model: T,
-  preUpdate: () => void,
-  serverUpdate: () => Promise<U>,
-  postUpdate?: (res: U) => void,
-): Promise<void> => {
-  if (ongoingActions.has(model)) {
-    return
-  }
-  ongoingActions.add(model)
-
-  const prevState: Map<string, any> = new Map<string, any>()
-  const dispose = deepObserve(model, (change, path) => {
-    if (change.observableKind === 'object') {
-      if (change.type === 'update') {
-        prevState.set(
-          [path, change.name].filter(Boolean).join('.'),
-          change.oldValue,
-        )
-      } else if (change.type === 'add') {
-        prevState.set([path, change.name].filter(Boolean).join('.'), undefined)
-      }
-    }
-  })
-  preUpdate()
-  dispose()
-
-  try {
-    const res = await serverUpdate()
-    runInAction(() => {
-      postUpdate?.(res)
-    })
-  } catch (error) {
-    runInAction(() => {
-      prevState.forEach((value, path) => {
-        set(model, path, value)
-      })
-    })
-    throw error
-  } finally {
-    ongoingActions.delete(model)
-  }
-}
diff --git a/src/lib/link-meta/bsky.ts b/src/lib/link-meta/bsky.ts
index 78d755331..322b02332 100644
--- a/src/lib/link-meta/bsky.ts
+++ b/src/lib/link-meta/bsky.ts
@@ -1,9 +1,8 @@
-import {AppBskyFeedPost} from '@atproto/api'
+import {AppBskyFeedPost, BskyAgent} from '@atproto/api'
 import * as apilib from 'lib/api/index'
 import {LikelyType, LinkMeta} from './link-meta'
 // import {match as matchRoute} from 'view/routes'
 import {convertBskyAppUrlIfNeeded, makeRecordUri} from '../strings/url-helpers'
-import {RootStoreModel} from 'state/index'
 import {ComposerOptsQuote} from 'state/shell/composer'
 import {useGetPost} from '#/state/queries/post'
 
@@ -23,7 +22,7 @@ import {useGetPost} from '#/state/queries/post'
 // remove once that's implemented
 // -prf
 export async function extractBskyMeta(
-  store: RootStoreModel,
+  agent: BskyAgent,
   url: string,
 ): Promise<LinkMeta> {
   url = convertBskyAppUrlIfNeeded(url)
@@ -120,13 +119,13 @@ export async function getPostAsQuote(
 }
 
 export async function getFeedAsEmbed(
-  store: RootStoreModel,
+  agent: BskyAgent,
   url: string,
 ): Promise<apilib.ExternalEmbedDraft> {
   url = convertBskyAppUrlIfNeeded(url)
   const [_0, user, _1, rkey] = url.split('/').filter(Boolean)
   const feed = makeRecordUri(user, 'app.bsky.feed.generator', rkey)
-  const res = await store.agent.app.bsky.feed.getFeedGenerator({feed})
+  const res = await agent.app.bsky.feed.getFeedGenerator({feed})
   return {
     isLoading: false,
     uri: feed,
@@ -146,13 +145,13 @@ export async function getFeedAsEmbed(
 }
 
 export async function getListAsEmbed(
-  store: RootStoreModel,
+  agent: BskyAgent,
   url: string,
 ): Promise<apilib.ExternalEmbedDraft> {
   url = convertBskyAppUrlIfNeeded(url)
   const [_0, user, _1, rkey] = url.split('/').filter(Boolean)
   const list = makeRecordUri(user, 'app.bsky.graph.list', rkey)
-  const res = await store.agent.app.bsky.graph.getList({list})
+  const res = await agent.app.bsky.graph.getList({list})
   return {
     isLoading: false,
     uri: list,
diff --git a/src/lib/link-meta/link-meta.ts b/src/lib/link-meta/link-meta.ts
index c490fa292..c17dee51f 100644
--- a/src/lib/link-meta/link-meta.ts
+++ b/src/lib/link-meta/link-meta.ts
@@ -1,5 +1,5 @@
+import {BskyAgent} from '@atproto/api'
 import {isBskyAppUrl} from '../strings/url-helpers'
-import {RootStoreModel} from 'state/index'
 import {extractBskyMeta} from './bsky'
 import {LINK_META_PROXY} from 'lib/constants'
 
@@ -23,12 +23,12 @@ export interface LinkMeta {
 }
 
 export async function getLinkMeta(
-  store: RootStoreModel,
+  agent: BskyAgent,
   url: string,
   timeout = 5e3,
 ): Promise<LinkMeta> {
   if (isBskyAppUrl(url)) {
-    return extractBskyMeta(store, url)
+    return extractBskyMeta(agent, url)
   }
 
   let urlp
@@ -55,9 +55,9 @@ export async function getLinkMeta(
     const to = setTimeout(() => controller.abort(), timeout || 5e3)
 
     const response = await fetch(
-      `${LINK_META_PROXY(
-        store.session.currentSession?.service || '',
-      )}${encodeURIComponent(url)}`,
+      `${LINK_META_PROXY(agent.service.toString() || '')}${encodeURIComponent(
+        url,
+      )}`,
       {signal: controller.signal},
     )
 
diff --git a/src/lib/media/image-sizes.ts b/src/lib/media/image-sizes.ts
new file mode 100644
index 000000000..4ea95ea23
--- /dev/null
+++ b/src/lib/media/image-sizes.ts
@@ -0,0 +1,34 @@
+import {Image} from 'react-native'
+import type {Dimensions} from 'lib/media/types'
+
+const sizes: Map<string, Dimensions> = new Map()
+const activeRequests: Map<string, Promise<Dimensions>> = new Map()
+
+export function get(uri: string): Dimensions | undefined {
+  return sizes.get(uri)
+}
+
+export async function fetch(uri: string): Promise<Dimensions> {
+  const Dimensions = sizes.get(uri)
+  if (Dimensions) {
+    return Dimensions
+  }
+
+  const prom =
+    activeRequests.get(uri) ||
+    new Promise<Dimensions>(resolve => {
+      Image.getSize(
+        uri,
+        (width: number, height: number) => resolve({width, height}),
+        (err: any) => {
+          console.error('Failed to fetch image dimensions for', uri, err)
+          resolve({width: 0, height: 0})
+        },
+      )
+    })
+  activeRequests.set(uri, prom)
+  const res = await prom
+  activeRequests.delete(uri)
+  sizes.set(uri, res)
+  return res
+}
diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts
index 106d2ca31..d06bd8028 100644
--- a/src/lib/strings/url-helpers.ts
+++ b/src/lib/strings/url-helpers.ts
@@ -1,5 +1,5 @@
 import {AtUri} from '@atproto/api'
-import {PROD_SERVICE} from 'state/index'
+import {PROD_SERVICE} from 'lib/constants'
 import TLDs from 'tlds'
 import psl from 'psl'