chore(refactor): replace authContoller with useAuth hook
This commit is contained in:
parent
2248128001
commit
0cc1a32059
15
src/App.tsx
15
src/App.tsx
@ -1,17 +1,21 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useAppSelector } from './hooks'
|
||||
import { Navigate, Route, Routes } from 'react-router-dom'
|
||||
import { AuthController } from './controllers'
|
||||
|
||||
import { useAppSelector, useAuth } from './hooks'
|
||||
|
||||
import { MainLayout } from './layouts/Main'
|
||||
|
||||
import { appPrivateRoutes, appPublicRoutes } from './routes'
|
||||
import './App.scss'
|
||||
import {
|
||||
privateRoutes,
|
||||
publicRoutes,
|
||||
recursiveRouteRenderer
|
||||
} from './routes/util'
|
||||
|
||||
import './App.scss'
|
||||
|
||||
const App = () => {
|
||||
const { checkSession } = useAuth()
|
||||
const authState = useAppSelector((state) => state.auth)
|
||||
|
||||
useEffect(() => {
|
||||
@ -22,9 +26,8 @@ const App = () => {
|
||||
window.location.hostname = 'localhost'
|
||||
}
|
||||
|
||||
const authController = new AuthController()
|
||||
authController.checkSession()
|
||||
}, [])
|
||||
checkSession()
|
||||
}, [checkSession])
|
||||
|
||||
const handleRootRedirect = () => {
|
||||
if (authState.loggedIn) return appPrivateRoutes.homePage
|
||||
|
@ -1,153 +0,0 @@
|
||||
import { EventTemplate } from 'nostr-tools'
|
||||
import { MetadataController, NostrController } from '.'
|
||||
import { appPrivateRoutes } from '../routes'
|
||||
import {
|
||||
setAuthState,
|
||||
setMetadataEvent,
|
||||
setRelayMapAction
|
||||
} from '../store/actions'
|
||||
import store from '../store/store'
|
||||
import { SignedEvent } from '../types'
|
||||
import {
|
||||
base64DecodeAuthToken,
|
||||
base64EncodeSignedEvent,
|
||||
compareObjects,
|
||||
getAuthToken,
|
||||
getRelayMap,
|
||||
saveAuthToken,
|
||||
unixNow
|
||||
} from '../utils'
|
||||
|
||||
export class AuthController {
|
||||
private nostrController: NostrController
|
||||
private metadataController: MetadataController
|
||||
|
||||
constructor() {
|
||||
this.nostrController = NostrController.getInstance()
|
||||
this.metadataController = MetadataController.getInstance()
|
||||
}
|
||||
|
||||
/**
|
||||
* Function will authenticate user by signing an auth event
|
||||
* which is done by calling the sign() function, where appropriate
|
||||
* method will be chosen (extension or keys)
|
||||
*
|
||||
* @param pubkey of the user trying to login
|
||||
* @returns url to redirect if authentication successfull
|
||||
* or error if otherwise
|
||||
*/
|
||||
async authAndGetMetadataAndRelaysMap(pubkey: string) {
|
||||
const emptyMetadata = this.metadataController.getEmptyMetadataEvent()
|
||||
|
||||
this.metadataController
|
||||
.findMetadata(pubkey)
|
||||
.then((event) => {
|
||||
if (event) {
|
||||
store.dispatch(setMetadataEvent(event))
|
||||
} else {
|
||||
store.dispatch(setMetadataEvent(emptyMetadata))
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('Error occurred while finding metadata', err)
|
||||
|
||||
store.dispatch(setMetadataEvent(emptyMetadata))
|
||||
})
|
||||
|
||||
// Nostr uses unix timestamps
|
||||
const timestamp = unixNow()
|
||||
const { href } = window.location
|
||||
|
||||
const authEvent: EventTemplate = {
|
||||
kind: 27235,
|
||||
tags: [
|
||||
['u', href],
|
||||
['method', 'GET']
|
||||
],
|
||||
content: '',
|
||||
created_at: timestamp
|
||||
}
|
||||
|
||||
const signedAuthEvent = await this.nostrController.signEvent(authEvent)
|
||||
this.createAndSaveAuthToken(signedAuthEvent)
|
||||
|
||||
store.dispatch(
|
||||
setAuthState({
|
||||
loggedIn: true,
|
||||
usersPubkey: pubkey
|
||||
})
|
||||
)
|
||||
|
||||
const relayMap = await getRelayMap(pubkey)
|
||||
|
||||
if (Object.keys(relayMap).length < 1) {
|
||||
// Navigate user to relays page if relay map is empty
|
||||
return Promise.resolve(appPrivateRoutes.relays)
|
||||
}
|
||||
|
||||
if (store.getState().auth.loggedIn) {
|
||||
if (!compareObjects(store.getState().relays?.map, relayMap.map))
|
||||
store.dispatch(setRelayMapAction(relayMap.map))
|
||||
}
|
||||
|
||||
/**
|
||||
* This block was added before we started using the `nostr-login` package
|
||||
* At this point it seems it's not needed anymore and it's even blocking the flow (reloading on /verify)
|
||||
* TODO to remove this if app works fine
|
||||
*/
|
||||
// const currentLocation = window.location.hash.replace('#', '')
|
||||
|
||||
// if (!Object.values(appPrivateRoutes).includes(currentLocation)) {
|
||||
// // Since verify is both public and private route, we don't use the `visitedLink`
|
||||
// // value for it. Otherwise, when linking to /verify/:id we get redirected
|
||||
// // to the root `/`
|
||||
// if (currentLocation.includes(appPublicRoutes.verify)) {
|
||||
// return Promise.resolve(currentLocation)
|
||||
// }
|
||||
//
|
||||
// // User did change the location to one of the private routes
|
||||
// const visitedLink = getVisitedLink()
|
||||
//
|
||||
// if (visitedLink) {
|
||||
// const { pathname, search } = visitedLink
|
||||
//
|
||||
// return Promise.resolve(`${pathname}${search}`)
|
||||
// } else {
|
||||
// // Navigate user in
|
||||
// return Promise.resolve(appPrivateRoutes.homePage)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
checkSession() {
|
||||
const savedAuthToken = getAuthToken()
|
||||
|
||||
if (savedAuthToken) {
|
||||
const signedEvent = base64DecodeAuthToken(savedAuthToken)
|
||||
|
||||
store.dispatch(
|
||||
setAuthState({
|
||||
loggedIn: true,
|
||||
usersPubkey: signedEvent.pubkey
|
||||
})
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
store.dispatch(
|
||||
setAuthState({
|
||||
loggedIn: false,
|
||||
usersPubkey: undefined
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private createAndSaveAuthToken(signedAuthEvent: SignedEvent) {
|
||||
const base64Encoded = base64EncodeSignedEvent(signedAuthEvent)
|
||||
|
||||
// save newly created auth token (base64 nostr singed event) in local storage along with expiry time
|
||||
saveAuthToken(base64Encoded)
|
||||
return base64Encoded
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
export * from './store'
|
||||
export * from './useAuth'
|
||||
export * from './useDidMount'
|
||||
export * from './useDvm'
|
||||
export * from './useLogout'
|
||||
export * from './useNDKContext'
|
||||
|
127
src/hooks/useAuth.ts
Normal file
127
src/hooks/useAuth.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { Event, EventTemplate } from 'nostr-tools'
|
||||
import { useCallback } from 'react'
|
||||
import { NostrController } from '../controllers'
|
||||
import { appPrivateRoutes } from '../routes'
|
||||
import {
|
||||
setAuthState,
|
||||
setMetadataEvent,
|
||||
setRelayMapAction
|
||||
} from '../store/actions'
|
||||
import {
|
||||
base64DecodeAuthToken,
|
||||
compareObjects,
|
||||
createAndSaveAuthToken,
|
||||
getAuthToken,
|
||||
getEmptyMetadataEvent,
|
||||
getRelayMap,
|
||||
unixNow
|
||||
} from '../utils'
|
||||
import { useAppDispatch, useAppSelector } from './store'
|
||||
import { useNDKContext } from './useNDKContext'
|
||||
|
||||
export const useAuth = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const { findMetadata } = useNDKContext()
|
||||
|
||||
const { auth: authState, relays: relaysState } = useAppSelector(
|
||||
(state) => state
|
||||
)
|
||||
|
||||
const checkSession = useCallback(() => {
|
||||
const savedAuthToken = getAuthToken()
|
||||
|
||||
if (savedAuthToken) {
|
||||
const signedEvent = base64DecodeAuthToken(savedAuthToken)
|
||||
|
||||
dispatch(
|
||||
setAuthState({
|
||||
loggedIn: true,
|
||||
usersPubkey: signedEvent.pubkey
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(
|
||||
setAuthState({
|
||||
loggedIn: false,
|
||||
usersPubkey: undefined
|
||||
})
|
||||
)
|
||||
}, [dispatch])
|
||||
|
||||
/**
|
||||
* Function will authenticate user by signing an auth event
|
||||
* which is done by calling the sign() function, where appropriate
|
||||
* method will be chosen (extension or keys)
|
||||
*
|
||||
* @param pubkey of the user trying to login
|
||||
* @returns url to redirect if authentication successfull
|
||||
* or error if otherwise
|
||||
*/
|
||||
const authAndGetMetadataAndRelaysMap = useCallback(
|
||||
async (pubkey: string) => {
|
||||
const emptyMetadata = getEmptyMetadataEvent()
|
||||
|
||||
try {
|
||||
const profile = await findMetadata(pubkey, {}, true)
|
||||
|
||||
if (profile && profile.profileEvent) {
|
||||
const event: Event = JSON.parse(profile.profileEvent)
|
||||
dispatch(setMetadataEvent(event))
|
||||
} else {
|
||||
dispatch(setMetadataEvent(emptyMetadata))
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Error occurred while finding metadata', err)
|
||||
dispatch(setMetadataEvent(emptyMetadata))
|
||||
}
|
||||
|
||||
const timestamp = unixNow()
|
||||
const { href } = window.location
|
||||
|
||||
const authEvent: EventTemplate = {
|
||||
kind: 27235,
|
||||
tags: [
|
||||
['u', href],
|
||||
['method', 'GET']
|
||||
],
|
||||
content: '',
|
||||
created_at: timestamp
|
||||
}
|
||||
|
||||
const nostrController = NostrController.getInstance()
|
||||
const signedAuthEvent = await nostrController.signEvent(authEvent)
|
||||
createAndSaveAuthToken(signedAuthEvent)
|
||||
|
||||
dispatch(
|
||||
setAuthState({
|
||||
loggedIn: true,
|
||||
usersPubkey: pubkey
|
||||
})
|
||||
)
|
||||
|
||||
const relayMap = await getRelayMap(pubkey)
|
||||
|
||||
if (Object.keys(relayMap).length < 1) {
|
||||
// Navigate user to relays page if relay map is empty
|
||||
return appPrivateRoutes.relays
|
||||
}
|
||||
|
||||
if (
|
||||
authState.loggedIn &&
|
||||
!compareObjects(relaysState?.map, relayMap.map)
|
||||
) {
|
||||
dispatch(setRelayMapAction(relayMap.map))
|
||||
}
|
||||
|
||||
return appPrivateRoutes.homePage
|
||||
},
|
||||
[dispatch, findMetadata, authState, relaysState]
|
||||
)
|
||||
|
||||
return {
|
||||
authAndGetMetadataAndRelaysMap,
|
||||
checkSession
|
||||
}
|
||||
}
|
@ -1,13 +1,18 @@
|
||||
import { Event, getPublicKey, kinds, nip19 } from 'nostr-tools'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { Outlet, useNavigate, useSearchParams } from 'react-router-dom'
|
||||
|
||||
import { Event, getPublicKey, kinds, nip19 } from 'nostr-tools'
|
||||
|
||||
import { init as initNostrLogin } from 'nostr-login'
|
||||
import { NostrLoginAuthOptions } from 'nostr-login/dist/types'
|
||||
|
||||
import { AppBar } from '../components/AppBar/AppBar'
|
||||
import { LoadingSpinner } from '../components/LoadingSpinner'
|
||||
import {
|
||||
AuthController,
|
||||
MetadataController,
|
||||
NostrController
|
||||
} from '../controllers'
|
||||
|
||||
import { MetadataController, NostrController } from '../controllers'
|
||||
|
||||
import { useAppDispatch, useAppSelector, useAuth, useLogout } from '../hooks'
|
||||
|
||||
import {
|
||||
restoreState,
|
||||
setMetadataEvent,
|
||||
@ -16,25 +21,25 @@ import {
|
||||
updateNostrLoginAuthMethod,
|
||||
updateUserAppData
|
||||
} from '../store/actions'
|
||||
import { LoginMethod } from '../store/auth/types'
|
||||
import { setUserRobotImage } from '../store/userRobotImage/action'
|
||||
|
||||
import {
|
||||
getRoboHashPicture,
|
||||
getUsersAppData,
|
||||
loadState,
|
||||
subscribeForSigits
|
||||
} from '../utils'
|
||||
import { useAppDispatch, useAppSelector } from '../hooks'
|
||||
|
||||
import styles from './style.module.scss'
|
||||
import { useLogout } from '../hooks/useLogout'
|
||||
import { LoginMethod } from '../store/auth/types'
|
||||
import { NostrLoginAuthOptions } from 'nostr-login/dist/types'
|
||||
import { init as initNostrLogin } from 'nostr-login'
|
||||
|
||||
export const MainLayout = () => {
|
||||
const [searchParams, setSearchParams] = useSearchParams()
|
||||
const navigate = useNavigate()
|
||||
const dispatch = useAppDispatch()
|
||||
const logout = useLogout()
|
||||
const { authAndGetMetadataAndRelaysMap } = useAuth()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState(`Loading App`)
|
||||
const isLoggedIn = useAppSelector((state) => state.auth?.loggedIn)
|
||||
@ -59,13 +64,11 @@ export const MainLayout = () => {
|
||||
|
||||
const login = useCallback(async () => {
|
||||
const nostrController = NostrController.getInstance()
|
||||
const authController = new AuthController()
|
||||
const pubkey = await nostrController.capturePublicKey()
|
||||
|
||||
dispatch(updateLoginMethod(LoginMethod.nostrLogin))
|
||||
|
||||
const redirectPath =
|
||||
await authController.authAndGetMetadataAndRelaysMap(pubkey)
|
||||
const redirectPath = await authAndGetMetadataAndRelaysMap(pubkey)
|
||||
|
||||
if (redirectPath) {
|
||||
navigateAfterLogin(redirectPath)
|
||||
@ -105,13 +108,10 @@ export const MainLayout = () => {
|
||||
)
|
||||
dispatch(updateLoginMethod(LoginMethod.privateKey))
|
||||
|
||||
const authController = new AuthController()
|
||||
authController
|
||||
.authAndGetMetadataAndRelaysMap(publickey)
|
||||
.catch((err) => {
|
||||
console.error('Error occurred in authentication: ' + err)
|
||||
return null
|
||||
})
|
||||
authAndGetMetadataAndRelaysMap(publickey).catch((err) => {
|
||||
console.error('Error occurred in authentication: ' + err)
|
||||
return null
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(`Error decoding the nsec. ${err}`)
|
||||
}
|
||||
|
@ -1,28 +1,28 @@
|
||||
import { launch as launchNostrLoginDialog } from 'nostr-login'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
|
||||
import { Button, Divider, TextField } from '@mui/material'
|
||||
import { getPublicKey, nip19 } from 'nostr-tools'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useAppDispatch } from '../../hooks/store'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
import { LoadingSpinner } from '../../components/LoadingSpinner'
|
||||
import { AuthController } from '../../controllers'
|
||||
import { updateKeyPair, updateLoginMethod } from '../../store/actions'
|
||||
import { KeyboardCode } from '../../types'
|
||||
import { LoginMethod } from '../../store/auth/types'
|
||||
|
||||
import { hexToBytes } from '@noble/hashes/utils'
|
||||
import { launch as launchNostrLoginDialog } from 'nostr-login'
|
||||
import { getPublicKey, nip19 } from 'nostr-tools'
|
||||
|
||||
import { LoadingSpinner } from '../../components/LoadingSpinner'
|
||||
import { useAppDispatch, useAuth } from '../../hooks'
|
||||
import { updateKeyPair, updateLoginMethod } from '../../store/actions'
|
||||
import { LoginMethod } from '../../store/auth/types'
|
||||
import { KeyboardCode } from '../../types'
|
||||
|
||||
import styles from './styles.module.scss'
|
||||
|
||||
export const Nostr = () => {
|
||||
const [searchParams] = useSearchParams()
|
||||
const { authAndGetMetadataAndRelaysMap } = useAuth()
|
||||
|
||||
const dispatch = useAppDispatch()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const authController = new AuthController()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
@ -102,12 +102,12 @@ export const Nostr = () => {
|
||||
setIsLoading(true)
|
||||
setLoadingSpinnerDesc('Authenticating and finding metadata')
|
||||
|
||||
const redirectPath = await authController
|
||||
.authAndGetMetadataAndRelaysMap(publickey)
|
||||
.catch((err) => {
|
||||
const redirectPath = await authAndGetMetadataAndRelaysMap(publickey).catch(
|
||||
(err) => {
|
||||
toast.error('Error occurred in authentication: ' + err)
|
||||
return null
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (redirectPath) navigateAfterLogin(redirectPath)
|
||||
|
||||
|
44
src/utils/auth.ts
Normal file
44
src/utils/auth.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { Event } from 'nostr-tools'
|
||||
import { SignedEvent } from '../types'
|
||||
import { saveAuthToken } from './localStorage'
|
||||
|
||||
export const base64EncodeSignedEvent = (event: SignedEvent) => {
|
||||
try {
|
||||
const authEventSerialized = JSON.stringify(event)
|
||||
const token = btoa(authEventSerialized)
|
||||
return token
|
||||
} catch (error) {
|
||||
throw new Error('An error occurred in JSON.stringify of signedAuthEvent')
|
||||
}
|
||||
}
|
||||
|
||||
export const base64DecodeAuthToken = (authToken: string): SignedEvent => {
|
||||
const decodedToken = atob(authToken)
|
||||
|
||||
try {
|
||||
const signedEvent = JSON.parse(decodedToken)
|
||||
return signedEvent
|
||||
} catch (error) {
|
||||
throw new Error('An error occurred in JSON.parse of the auth token')
|
||||
}
|
||||
}
|
||||
|
||||
export const createAndSaveAuthToken = (signedAuthEvent: SignedEvent) => {
|
||||
const base64Encoded = base64EncodeSignedEvent(signedAuthEvent)
|
||||
|
||||
// save newly created auth token (base64 nostr signed event) in local storage along with expiry time
|
||||
saveAuthToken(base64Encoded)
|
||||
return base64Encoded
|
||||
}
|
||||
|
||||
export const getEmptyMetadataEvent = (pubkey?: string): Event => {
|
||||
return {
|
||||
content: '',
|
||||
created_at: new Date().valueOf(),
|
||||
id: '',
|
||||
kind: 0,
|
||||
pubkey: pubkey || '',
|
||||
sig: '',
|
||||
tags: []
|
||||
}
|
||||
}
|
140
src/utils/dvm.ts
140
src/utils/dvm.ts
@ -1,140 +1,10 @@
|
||||
import { EventTemplate, Filter, kinds, nip19 } from 'nostr-tools'
|
||||
import { compareObjects, queryNip05, unixNow } from '.'
|
||||
import {
|
||||
MetadataController,
|
||||
NostrController,
|
||||
relayController
|
||||
} from '../controllers'
|
||||
import { NostrJoiningBlock, RelayInfoObject } from '../types'
|
||||
import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'
|
||||
import store from '../store/store'
|
||||
import { EventTemplate } from 'nostr-tools'
|
||||
import { compareObjects, unixNow } from '.'
|
||||
import { NostrController, relayController } from '../controllers'
|
||||
import { setRelayInfoAction } from '../store/actions'
|
||||
|
||||
export const getNostrJoiningBlockNumber = async (
|
||||
hexKey: string
|
||||
): Promise<NostrJoiningBlock | null> => {
|
||||
const metadataController = MetadataController.getInstance()
|
||||
|
||||
const relaySet = await metadataController.findRelayListMetadata(hexKey)
|
||||
|
||||
const userRelays: string[] = []
|
||||
|
||||
// find user's relays
|
||||
if (relaySet.write.length > 0) {
|
||||
userRelays.push(...relaySet.write)
|
||||
} else {
|
||||
const metadata = await metadataController.findMetadata(hexKey)
|
||||
if (!metadata) return null
|
||||
|
||||
const metadataContent =
|
||||
metadataController.extractProfileMetadataContent(metadata)
|
||||
|
||||
if (metadataContent?.nip05) {
|
||||
const nip05Profile = await queryNip05(metadataContent.nip05)
|
||||
|
||||
if (nip05Profile && nip05Profile.pubkey === hexKey) {
|
||||
userRelays.push(...nip05Profile.relays)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (userRelays.length === 0) return null
|
||||
|
||||
// filter for finding user's first kind 0 event
|
||||
const eventFilter: Filter = {
|
||||
kinds: [kinds.Metadata],
|
||||
authors: [hexKey]
|
||||
}
|
||||
|
||||
// find user's kind 0 event published on user's relays
|
||||
const event = await relayController.fetchEvent(eventFilter, userRelays)
|
||||
|
||||
if (event) {
|
||||
const { created_at } = event
|
||||
|
||||
// initialize job request
|
||||
const jobEventTemplate: EventTemplate = {
|
||||
content: '',
|
||||
created_at: unixNow(),
|
||||
kind: 68001,
|
||||
tags: [
|
||||
['i', `${created_at * 1000}`],
|
||||
['j', 'blockChain-block-number']
|
||||
]
|
||||
}
|
||||
|
||||
const nostrController = NostrController.getInstance()
|
||||
|
||||
// sign job request event
|
||||
const jobSignedEvent = await nostrController.signEvent(jobEventTemplate)
|
||||
|
||||
const relays = [
|
||||
'wss://relay.damus.io',
|
||||
'wss://relay.primal.net',
|
||||
'wss://relayable.org'
|
||||
]
|
||||
|
||||
await relayController.publish(jobSignedEvent, relays).catch((err) => {
|
||||
console.error(
|
||||
'Error occurred in publish blockChain-block-number DVM job',
|
||||
err
|
||||
)
|
||||
})
|
||||
|
||||
const subscribeWithTimeout = (
|
||||
subscription: NDKSubscription,
|
||||
timeoutMs: number
|
||||
): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const eventHandler = (event: NDKEvent) => {
|
||||
subscription.stop()
|
||||
resolve(event.content)
|
||||
}
|
||||
|
||||
subscription.on('event', eventHandler)
|
||||
|
||||
// Set up a timeout to stop the subscription after a specified time
|
||||
const timeout = setTimeout(() => {
|
||||
subscription.stop() // Stop the subscription
|
||||
reject(new Error('Subscription timed out')) // Reject the promise with a timeout error
|
||||
}, timeoutMs)
|
||||
|
||||
// Handle subscription close event
|
||||
subscription.on('close', () => clearTimeout(timeout))
|
||||
})
|
||||
}
|
||||
|
||||
const dvmNDK = new NDK({
|
||||
explicitRelayUrls: relays
|
||||
})
|
||||
|
||||
await dvmNDK.connect(2000)
|
||||
|
||||
// filter for getting DVM job's result
|
||||
const sub = dvmNDK.subscribe({
|
||||
kinds: [68002 as number],
|
||||
'#e': [jobSignedEvent.id],
|
||||
'#p': [jobSignedEvent.pubkey]
|
||||
})
|
||||
|
||||
// asynchronously get block number from dvm job with 20 seconds timeout
|
||||
const dvmJobResult = await subscribeWithTimeout(sub, 20000)
|
||||
|
||||
const encodedEventPointer = nip19.neventEncode({
|
||||
id: event.id,
|
||||
relays: userRelays,
|
||||
author: event.pubkey,
|
||||
kind: event.kind
|
||||
})
|
||||
|
||||
return {
|
||||
block: parseInt(dvmJobResult),
|
||||
encodedEventPointer
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
import store from '../store/store'
|
||||
import { RelayInfoObject } from '../types'
|
||||
|
||||
/**
|
||||
* Sets information about relays into relays.info app state.
|
||||
|
@ -1,3 +1,5 @@
|
||||
export * from './auth'
|
||||
export * from './const'
|
||||
export * from './crypto'
|
||||
export * from './dvm'
|
||||
export * from './hash'
|
||||
@ -11,4 +13,3 @@ export * from './string'
|
||||
export * from './url'
|
||||
export * from './utils'
|
||||
export * from './zip'
|
||||
export * from './const'
|
||||
|
@ -199,27 +199,6 @@ export const queryNip05 = async (
|
||||
}
|
||||
}
|
||||
|
||||
export const base64EncodeSignedEvent = (event: SignedEvent) => {
|
||||
try {
|
||||
const authEventSerialized = JSON.stringify(event)
|
||||
const token = btoa(authEventSerialized)
|
||||
return token
|
||||
} catch (error) {
|
||||
throw new Error('An error occurred in JSON.stringify of signedAuthEvent')
|
||||
}
|
||||
}
|
||||
|
||||
export const base64DecodeAuthToken = (authToken: string): SignedEvent => {
|
||||
const decodedToken = atob(authToken)
|
||||
|
||||
try {
|
||||
const signedEvent = JSON.parse(decodedToken)
|
||||
return signedEvent
|
||||
} catch (error) {
|
||||
throw new Error('An error occurred in JSON.parse of the auth token')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pubkey in hex or npub format
|
||||
* @returns robohash.org url for the avatar
|
||||
@ -985,7 +964,7 @@ export const sendNotification = async (receiver: string, meta: Meta) => {
|
||||
*/
|
||||
export const getProfileUsername = (
|
||||
npub: `npub1${string}` | string,
|
||||
profile?: ProfileMetadata
|
||||
profile?: ProfileMetadata // todo: use NDKUserProfile
|
||||
) =>
|
||||
truncate(profile?.display_name || profile?.name || hexToNpub(npub), {
|
||||
length: 16
|
||||
|
Loading…
Reference in New Issue
Block a user