about summary refs log tree commit diff
path: root/src/state/lib
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-02-22 14:23:57 -0600
committerGitHub <noreply@github.com>2023-02-22 14:23:57 -0600
commitf28334739b107f3e9f7b6ca2670778dba280600d (patch)
tree4e1563242e1a041c5d5483ab018123170dcb3fc8 /src/state/lib
parent7916b26aadb7e003728d9dc653ab8b8deabf4076 (diff)
downloadvoidsky-f28334739b107f3e9f7b6ca2670778dba280600d.tar.zst
Merge main into the Web PR (#230)
* Update to RN 71.1.0 (#100)

* Update to RN 71

* Adds missing lint plugin

* Add missing native changes

* Bump @atproto/api@0.0.7 (#112)

* Image not loading on swipe (#114)

* Adds prefetching to images

* Adds image prefetch

* bugfix for images not showing on swipe

* Fixes prefetch bug

* Update src/view/com/util/PostEmbeds.tsx

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* Fixes to session management (#117)

* Update session-management to solve incorrectly dropped sessions

* Reset the nav on account switch

* Reset the feed on me.load()

* Update tests to reflect new account-switching behavior

* Increase max image resolutions and sizes (#118)

* Slightly increase the hitslop for post controls

* Fix character counter color in dark mode

* Update login to use new session.create api, which enables email login (close #93) (#119)

* Replaces the alert with dropdown for profile image and banner (#123)

* replaces the alert with dropdown for profile image and banner

* lint

* Fix to ordering of images in the embed grid (#121)

* Add explicit link-embed controls to the composer (#120)

* Add explicit link-embed controls

* Update the target rez/size of link embed thumbs

* Remove the alert before publishing without a link card

* [Draft] Fixes image failing on reupload issue (#128)

* Fixes image failing on reupload issue

* Use tmp folder instead of documents

* lint

* Image performance improvements (#126)

* Switch out most images for FastImage

* Add image loading placeholders

* Fix tests

* Collection of fixes to list rendering (#127)

* Fix bug that caused endless spinners in profile feeds

* Bundle fetches of suggested actors into one update

* Fixes to suggested follow rendering

* Fix missing replacement of flex:1 to height:100

* Fixes to navigation swipes (#129)

* Nav swipe: increase the distance traveled in response to gesture movement.

This causes swipes to feel faster and more responsive.

* Fix: fully clamp the swipe against the edge

* Improve the performance of swipes by skipping the interaction manager

* Adds dark mode to the edit screen (#130)

* Adds dark mode to edit screen

* lint

* lint

* lint

* Reduce render cost of post controls and improve perceived responsiveness (#132)

* Move post control animations into conditional render and increase perceived responsiveness

* Remove log

* Adds dark mode to the dropdown (#131)

* Adds dark mode to the bottom sheet

* Make background button lighter (like before)

* lint

* Fix bug in lightbox rendering (#133)

* Fix layout in onboarding to not overflow the footer

* Configure feed FlatList (removeClippedSubviews=true) to improve scroll performance (#136)

* Disable like/repost animations to see if theyre causing #135 (#137)

* Composer: mention tagging now works in middle of text (close #105) (#139)

* Implement account deletion (#141)

* Fix photo & camera permission management (#140)

* Check photo & camera perms and alert the user if not available (close #64)

- Adds perms checks with a prompt to update settings if needed
- Moves initial access of photos in the composer so that the initial prompt
  occurs at an intuitive time.

* Add react-native-permissions test mock

* Fix issue causing multiple access requests

* Use longer var names

* Update podfile.lock

* Lint fix

* Move photo perm request in composer to the gallery btn instead of when the carousel is opened

* Adds more tracking all around the app (#142)

* Adds more tracking all around the app

* more events

* lint

* using better analytics naming

* missed file

* more fixes

* Calculate image aspect ratio on load (#146)

* Calculate image aspect ratio on load

* Move aspect ratio bounds to constants

* Adds detox testing and instructions (#147)

* Adds detox testing and instructions

* lint

* lint

* Error cleanup (close #79) (#148)

* Avoid surfacing errors to the user when it's not critical

* Remove now-unused GetAssertionsView

* Apply cleanError() consistently

* Give a better error message for Upstream Failures (http status 502)

* Hide errors in notifications because they're not useful

* More e2e tests (create account) (#150)

* Adds respots under the 'post' tab under profile (#158)

* Adds dark mode to delete account screen (#159)

* 87 dark mode edit profile (#162)

* Adds dark mode to delete account screen

* Adds one more missed darkmode

* more fixes

* Remove fallback gradient on external links without thumbs (#164)

* Remove fallback gradient on external links without thumbs

* Remove fallback gradient on external links without thumbs in the composer preview

* Fix refresh behavior around a series of models (repost, graph, vote) (#163)

* Fix refresh behavior around a series of models (repost, graph, vote)

* Fix cursor behavior in reposted-by view

* Fixes issue where retrying on image upload fails (#166)

* Fixes issue where retrying on image upload fails

* Lint, longer test time

* Longer waitfor time in tests

* even longer timeout

* longer timeout

* missed file

* Update src/view/com/composer/ComposePost.tsx

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* Update src/view/com/composer/ComposePost.tsx

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* 154 cached image profile (#167)

* Fixes issue where retrying on image upload fails

* Lint, longer test time

* Longer waitfor time in tests

* even longer timeout

* longer timeout

* missed file

* Fixes image cache error on second try for profile screen

* lint

* lint

* lint

* Refactor session management to use a new "Agent" API (#165)

* Add the atp-agent implementation (temporarily in this repo)

* Rewrite all session & API management to use the new atp-agent

* Update tests for the atp-agent refactor

* Refactor management of session-related state. Includes:
- More careful management of when state is cleared or fetched
- Debug logging to help trace future issues
- Clearer APIs overall

* Bubble session-expiration events to the user and display a toast to explain

* Switch to the new @atproto/api@0.1.0

* Minor aesthetic cleanup in SessionModel

* Wire up ReportAccount and ReportPost (#168)

* Fixes embeds for youtube channels (#169)

* Bump app ios version to 1.1 (needed after app store submission)

* Fix potential issues with promise guards when an error occurs (#170)

* Refactor models to use bundleAsync and lock regions (#171)

* Fix to an edge case with feed re-ordering for threads (#172)

* 151 fix youtube channel embed (#173)

* Fixes embeds for youtube channels

* Tests for youtube extract meta

* lint

* Add 'doesnt use non-exempt encryption' to ios config

* Rework the search UI and add  (#174)

* Add search tab and move icon to footer

* Remove subtitles from view header

* Remove unused code

* Clean up UI of search screen

* Search: give better user feedback to UI state and add a cancel button

* Add WhoToFollow section to search

* Add a temporary SuggestedPosts solution using the patented 'bsky team algo'

* Trigger reload of suggested content in search on open

* Wait five min between reloading discovery content

* Reduce weight of solid search icon in footer

* Fix lint

* Fix tests

* 151 feat youtube embed iframe (#176)

* youtube embed iframe temp commit

* Fixes styling and code cleanup

* lint

* Now clicking between the pause and settings button doesn't trigger the parent

* use modest branding (less yt logos)

* Stop playing the video once there's a navigation event

* Make sure the iframe is unmounted on any navigation event

* fixes tests

* lint

* Add scroll-to-top for all screens (#177)

* Adds hardcoded suggested list (#178)

* Adds hardcoded suggested list

* Update suggested-actors-view to support page sizes smaller than the hardcoded list

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* more robust centering of the play button (#181)

Co-authored-by: Aryan Goharzad <arrygoo@gmail.com>

* Bundle of UI modifications (#175)

* Adjust visual balance of SuggestedPosts and WhoToFollow

* Fix bug in the discovery load trigger

* Adjust search header aesthetic and have it scroll away

* More visual balance tweaks on the search page

* Even more visual balance tweaks on the search page

* Hide the footer on scroll in search

* Ditch the composer prompt buttons in the home feed

* Center the view header title

* Hide header on scroll on the home feed

* Fix e2e tests

* Fix home feed positioning (closes #189) (#195)

* Fix home feed positioning for floating header

* Fix positioning of errors in home feed

* Fix lint

* Don't show new-content notification for reposts (close #179) (#197)

* Show the splash screen during session resumption (close #186) (#199)

* Fix to suggested follows: chunk the hardcoded fetches to 25 at a time (close #196) (#198)

* UI updates to the floating action button (#201)

* Update FAB to use a plus icon and not drop shadow

* Update FAB positioning to be more consistent in different shell modes

* Animate the FAB's repositioning

* Remove the 'loading' placeholder from images as it degraded feed perf (#202)

* Remove the 'loading' placeholder from images as it degraded feed perf

* Remove references

* Fix RN bug that causes home feed not to load more; also fix home feed load view. (#208)

RN has a bug where rendering a flatlist with an empty array appears to break its
virtual list windowing behaviors. See https://stackoverflow.com/a/67873596

* Only give the loading spinner on the home feed during PTR (#207)

(cherry picked from commit b7a5da12fdfacef74873b5cf6d75f20d259bde0e)

* Implement our own lifecycle tracking to ensure it never fires while the app is backgrounded (close #193) (#211)

* Push notification fixes (#210)

* Fix to when screen analytics events are firing

* Fix: dont trigger update state when backgrounded

* Small fix to notifee API usage

* Fix: properly load notification info for push card

* Add feedback link to main menu (close #191) (#212)

* Add "follows you" information and sync follow state between views (#215)

* Bump @atproto/api@0.1.2 and update API usage

* Add 'follows you' pill to profile header (close #110)

* Add 'follows you' to followers and follows (close #103)

* Update reposted-by and liked-by views to use the same components as followers and following

* Create a local follows cache MyFollowsModel to keep views in sync (close #205)

* Add incremental hydration to the MyFollows model

* Fix tests

* Update deps

* Fix lint

* Fix to paginated fetches

* Fix reference

* Fix potential state-desync issue

* Fixes to notifications (#216)

* Improve push-notification for follows

* Refresh notifications on screen open (close #214)

* Avoid showing loader more than needed in post threads

* Refactor notification polling to handle view-state more effectively

* Delete a bunch of tests taht werent adding value

* Remove the accounts integration test; we'll use the e2e test instead

* Load latest in notifications when the screen is open rather than full refresh

* Randomize hard-coded suggested follows (#226)

* Ensure follows are loaded before filtering hardcoded suggestions

* Randomize hard-coded suggested profiles (close #219)

* Sanitizes posts on publish and render (#217)

* Sanatizes posts on publish and render

* lint

* lint and added sanitize to thread view as well

* adjusts indices based on replaced text

* Woops, fixes a bug

* bugfix + cleanup

* comment

* lint

* move sanitize text to later in the flow

* undo changes to compose post

* Add RichText library building upon the sanitizePost library method

* Add lodash.clonedeep dep

* Switch to RichText processing on record load & render

* Fix lint

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* A group of notifications fixes (#227)

* Fix: don't group together notifications that can't visually be grouped (close #221)

* Mark all notifications read on PTR

* Small optimization: useCallback and useMemo in posts feed

* Add loading spinner to footer of notifications (close #222)

* Fix to scrolling to posts within a thread (#228)

* Fix: render the entire thread at start so that scrollToIndex works always (close #270)

* Visual fixes to thread 'load more'

* A few small perf improvements to thread rendering

* Fix lint

* 1.2

* Remove unused logger lib

* Remove state-mock

* Type fixes

* Reorganize the folder structure for lib and switch to typescript path aliases

* Move build-flags into lib

* Move to the state path alias

* Add view path alias

* Fix lint

* iOS build fixes

* Wrap analytics in native/web splitter and re-enable in all view code

* Add web version of react-native-webview

* Add web split for version number

* Fix BlurView import for web

* Add web split for fastimage

* Create web split for permissions lib

* Fix for web high priority images

---------

Co-authored-by: Aryan Goharzad <arrygoo@gmail.com>
Diffstat (limited to 'src/state/lib')
-rw-r--r--src/state/lib/api-polyfill.ts79
-rw-r--r--src/state/lib/api-polyfill.web.ts4
-rw-r--r--src/state/lib/api.ts190
-rw-r--r--src/state/lib/bg-scheduler.ts18
-rw-r--r--src/state/lib/bg-scheduler.web.ts13
-rw-r--r--src/state/lib/storage.ts52
-rw-r--r--src/state/lib/type-guards.ts14
7 files changed, 0 insertions, 370 deletions
diff --git a/src/state/lib/api-polyfill.ts b/src/state/lib/api-polyfill.ts
deleted file mode 100644
index df397cbd9..000000000
--- a/src/state/lib/api-polyfill.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import {sessionClient as AtpApi} from '@atproto/api'
-import RNFS from 'react-native-fs'
-
-const TIMEOUT = 10e3 // 10s
-
-export function doPolyfill() {
-  AtpApi.xrpc.fetch = fetchHandler
-}
-
-interface FetchHandlerResponse {
-  status: number
-  headers: Record<string, string>
-  body: ArrayBuffer | undefined
-}
-
-async function fetchHandler(
-  reqUri: string,
-  reqMethod: string,
-  reqHeaders: Record<string, string>,
-  reqBody: any,
-): Promise<FetchHandlerResponse> {
-  const reqMimeType = reqHeaders['Content-Type'] || reqHeaders['content-type']
-  if (reqMimeType && reqMimeType.startsWith('application/json')) {
-    reqBody = JSON.stringify(reqBody)
-  } else if (
-    typeof reqBody === 'string' &&
-    (reqBody.startsWith('/') || reqBody.startsWith('file:'))
-  ) {
-    if (reqBody.endsWith('.jpeg') || reqBody.endsWith('.jpg')) {
-      // HACK
-      // React native has a bug that inflates the size of jpegs on upload
-      // we get around that by renaming the file ext to .bin
-      // see https://github.com/facebook/react-native/issues/27099
-      // -prf
-      const newPath = reqBody.replace(/\.jpe?g$/, '.bin')
-      await RNFS.moveFile(reqBody, newPath)
-      reqBody = newPath
-    }
-    // NOTE
-    // React native treats bodies with {uri: string} as file uploads to pull from cache
-    // -prf
-    reqBody = {uri: reqBody}
-  }
-
-  const controller = new AbortController()
-  const to = setTimeout(() => controller.abort(), TIMEOUT)
-
-  const res = await fetch(reqUri, {
-    method: reqMethod,
-    headers: reqHeaders,
-    body: reqBody,
-    signal: controller.signal,
-  })
-
-  const resStatus = res.status
-  const resHeaders: Record<string, string> = {}
-  res.headers.forEach((value: string, key: string) => {
-    resHeaders[key] = value
-  })
-  const resMimeType = resHeaders['Content-Type'] || resHeaders['content-type']
-  let resBody
-  if (resMimeType) {
-    if (resMimeType.startsWith('application/json')) {
-      resBody = await res.json()
-    } else if (resMimeType.startsWith('text/')) {
-      resBody = await res.text()
-    } else {
-      throw new Error('TODO: non-textual response body')
-    }
-  }
-
-  clearTimeout(to)
-
-  return {
-    status: resStatus,
-    headers: resHeaders,
-    body: resBody,
-  }
-}
diff --git a/src/state/lib/api-polyfill.web.ts b/src/state/lib/api-polyfill.web.ts
deleted file mode 100644
index 1469cf905..000000000
--- a/src/state/lib/api-polyfill.web.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export function doPolyfill() {
-  // TODO needed? native fetch may work fine -prf
-  // AtpApi.xrpc.fetch = fetchHandler
-}
diff --git a/src/state/lib/api.ts b/src/state/lib/api.ts
deleted file mode 100644
index 7ae04f52d..000000000
--- a/src/state/lib/api.ts
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * The environment is a place where services and shared dependencies between
- * models live. They are made available to every model via dependency injection.
- */
-
-// import {ReactNativeStore} from './auth'
-import {AppBskyEmbedImages, AppBskyEmbedExternal} from '@atproto/api'
-import {AtUri} from '../../third-party/uri'
-import {RootStoreModel} from '../models/root-store'
-import {extractEntities} from '../../lib/strings'
-import {isNetworkError} from '../../lib/errors'
-import {LinkMeta} from '../../lib/link-meta'
-import {Image} from '../../lib/images'
-
-export interface ExternalEmbedDraft {
-  uri: string
-  isLoading: boolean
-  meta?: LinkMeta
-  localThumb?: Image
-}
-
-export async function post(
-  store: RootStoreModel,
-  text: string,
-  replyTo?: string,
-  extLink?: ExternalEmbedDraft,
-  images?: string[],
-  knownHandles?: Set<string>,
-  onStateChange?: (state: string) => void,
-) {
-  let embed: AppBskyEmbedImages.Main | AppBskyEmbedExternal.Main | undefined
-  let reply
-
-  onStateChange?.('Processing...')
-  const entities = extractEntities(text, knownHandles)
-  if (entities) {
-    for (const ent of entities) {
-      if (ent.type === 'mention') {
-        const prof = await store.profiles.getProfile(ent.value)
-        ent.value = prof.data.did
-      }
-    }
-  }
-
-  if (images?.length) {
-    embed = {
-      $type: 'app.bsky.embed.images',
-      images: [],
-    } as AppBskyEmbedImages.Main
-    let i = 1
-    for (const image of images) {
-      onStateChange?.(`Uploading image #${i++}...`)
-      const res = await store.api.com.atproto.blob.upload(
-        image, // this will be special-cased by the fetch monkeypatch in /src/state/lib/api.ts
-        {encoding: 'image/jpeg'},
-      )
-      embed.images.push({
-        image: {
-          cid: res.data.cid,
-          mimeType: 'image/jpeg',
-        },
-        alt: '', // TODO supply alt text
-      })
-    }
-  }
-
-  if (!embed && extLink) {
-    let thumb
-    if (extLink.localThumb) {
-      onStateChange?.('Uploading link thumbnail...')
-      let encoding
-      if (extLink.localThumb.path.endsWith('.png')) {
-        encoding = 'image/png'
-      } else if (
-        extLink.localThumb.path.endsWith('.jpeg') ||
-        extLink.localThumb.path.endsWith('.jpg')
-      ) {
-        encoding = 'image/jpeg'
-      } else {
-        store.log.warn(
-          'Unexpected image format for thumbnail, skipping',
-          extLink.localThumb.path,
-        )
-      }
-      if (encoding) {
-        const thumbUploadRes = await store.api.com.atproto.blob.upload(
-          extLink.localThumb.path, // this will be special-cased by the fetch monkeypatch in /src/state/lib/api.ts
-          {encoding},
-        )
-        thumb = {
-          cid: thumbUploadRes.data.cid,
-          mimeType: encoding,
-        }
-      }
-    }
-    embed = {
-      $type: 'app.bsky.embed.external',
-      external: {
-        uri: extLink.uri,
-        title: extLink.meta?.title || '',
-        description: extLink.meta?.description || '',
-        thumb,
-      },
-    } as AppBskyEmbedExternal.Main
-  }
-
-  if (replyTo) {
-    const replyToUrip = new AtUri(replyTo)
-    const parentPost = await store.api.app.bsky.feed.post.get({
-      user: replyToUrip.host,
-      rkey: replyToUrip.rkey,
-    })
-    if (parentPost) {
-      const parentRef = {
-        uri: parentPost.uri,
-        cid: parentPost.cid,
-      }
-      reply = {
-        root: parentPost.value.reply?.root || parentRef,
-        parent: parentRef,
-      }
-    }
-  }
-
-  try {
-    onStateChange?.('Posting...')
-    return await store.api.app.bsky.feed.post.create(
-      {did: store.me.did || ''},
-      {
-        text,
-        reply,
-        embed,
-        entities,
-        createdAt: new Date().toISOString(),
-      },
-    )
-  } catch (e: any) {
-    console.error(`Failed to create post: ${e.toString()}`)
-    if (isNetworkError(e)) {
-      throw new Error(
-        'Post failed to upload. Please check your Internet connection and try again.',
-      )
-    } else {
-      throw e
-    }
-  }
-}
-
-export async function repost(store: RootStoreModel, uri: string, cid: string) {
-  return await store.api.app.bsky.feed.repost.create(
-    {did: store.me.did || ''},
-    {
-      subject: {uri, cid},
-      createdAt: new Date().toISOString(),
-    },
-  )
-}
-
-export async function unrepost(store: RootStoreModel, repostUri: string) {
-  const repostUrip = new AtUri(repostUri)
-  return await store.api.app.bsky.feed.repost.delete({
-    did: repostUrip.hostname,
-    rkey: repostUrip.rkey,
-  })
-}
-
-export async function follow(
-  store: RootStoreModel,
-  subjectDid: string,
-  subjectDeclarationCid: string,
-) {
-  return await store.api.app.bsky.graph.follow.create(
-    {did: store.me.did || ''},
-    {
-      subject: {
-        did: subjectDid,
-        declarationCid: subjectDeclarationCid,
-      },
-      createdAt: new Date().toISOString(),
-    },
-  )
-}
-
-export async function unfollow(store: RootStoreModel, followUri: string) {
-  const followUrip = new AtUri(followUri)
-  return await store.api.app.bsky.graph.follow.delete({
-    did: followUrip.hostname,
-    rkey: followUrip.rkey,
-  })
-}
diff --git a/src/state/lib/bg-scheduler.ts b/src/state/lib/bg-scheduler.ts
deleted file mode 100644
index 97ccb78b2..000000000
--- a/src/state/lib/bg-scheduler.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import BackgroundFetch, {
-  BackgroundFetchStatus,
-} from 'react-native-background-fetch'
-
-export function configure(
-  handler: (taskId: string) => Promise<void>,
-  timeoutHandler: (taskId: string) => Promise<void>,
-): Promise<BackgroundFetchStatus> {
-  return BackgroundFetch.configure(
-    {minimumFetchInterval: 15},
-    handler,
-    timeoutHandler,
-  )
-}
-
-export function finish(taskId: string) {
-  return BackgroundFetch.finish(taskId)
-}
diff --git a/src/state/lib/bg-scheduler.web.ts b/src/state/lib/bg-scheduler.web.ts
deleted file mode 100644
index 91ec9428f..000000000
--- a/src/state/lib/bg-scheduler.web.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-type BackgroundFetchStatus = 0 | 1 | 2
-
-export async function configure(
-  _handler: (taskId: string) => Promise<void>,
-  _timeoutHandler: (taskId: string) => Promise<void>,
-): Promise<BackgroundFetchStatus> {
-  // TODO
-  return 0
-}
-
-export function finish(_taskId: string) {
-  // TODO
-}
diff --git a/src/state/lib/storage.ts b/src/state/lib/storage.ts
deleted file mode 100644
index dc5fb620f..000000000
--- a/src/state/lib/storage.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import AsyncStorage from '@react-native-async-storage/async-storage'
-
-export async function loadString(key: string): Promise<string | null> {
-  try {
-    return await AsyncStorage.getItem(key)
-  } catch {
-    // not sure why this would fail... even reading the RN docs I'm unclear
-    return null
-  }
-}
-
-export async function saveString(key: string, value: string): Promise<boolean> {
-  try {
-    await AsyncStorage.setItem(key, value)
-    return true
-  } catch {
-    return false
-  }
-}
-
-export async function load(key: string): Promise<any | null> {
-  try {
-    const str = await AsyncStorage.getItem(key)
-    if (typeof str !== 'string') {
-      return null
-    }
-    return JSON.parse(str)
-  } catch {
-    return null
-  }
-}
-
-export async function save(key: string, value: any): Promise<boolean> {
-  try {
-    await AsyncStorage.setItem(key, JSON.stringify(value))
-    return true
-  } catch {
-    return false
-  }
-}
-
-export async function remove(key: string): Promise<void> {
-  try {
-    await AsyncStorage.removeItem(key)
-  } catch {}
-}
-
-export async function clear(): Promise<void> {
-  try {
-    await AsyncStorage.clear()
-  } catch {}
-}
diff --git a/src/state/lib/type-guards.ts b/src/state/lib/type-guards.ts
deleted file mode 100644
index 8fe651ffb..000000000
--- a/src/state/lib/type-guards.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-export function isObj(v: unknown): v is Record<string, unknown> {
-  return !!v && typeof v === 'object'
-}
-
-export function hasProp<K extends PropertyKey>(
-  data: object,
-  prop: K,
-): data is Record<K, unknown> {
-  return prop in data
-}
-
-export function isStrArray(v: unknown): v is string[] {
-  return Array.isArray(v) && v.every(item => typeof item === 'string')
-}