Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"connectkit": "^1.8.2",
"connectkit-next-siwe": "^0.3.0",
"iron-session": "^8.0.3",
"namestone-sdk": "^0.2.8",
"next": "14.2.6",
"next-safe-action": "^7.7.1",
"pinata-web3": "^0.4.1",
Expand Down
21 changes: 10 additions & 11 deletions src/actions/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { zfd } from 'zod-form-data'

import { actionClient } from '@/actions/client'
import { isAllowlisted } from '@/lib/allowlist'
import { namestoneFetch } from '@/lib/namestone'
import { namestone } from '@/lib/namestone'
import { extractErrorMessage } from '@/lib/utils'
import { NamestoneProfileSchema } from '@/types/namestone'

const formSchema = zfd.formData(NamestoneProfileSchema)
Expand Down Expand Up @@ -47,15 +48,13 @@ export const createName = actionClient
return { error: 'Name must be 3 - 12 alphanumeric characters' }
}

const res = await namestoneFetch<{ success?: boolean; error?: string }>({
path: 'claim-name?single_claim=1',
method: 'POST',
body: profile,
})

if (res.error) {
return { error: res.error }
try {
await namestone.claimName({ ...profile, single_claim: 1 })
return { success: true }
} catch (err) {
return {
error:
err instanceof Error ? extractErrorMessage(err) : 'Unknown error',
}
}

return res
})
34 changes: 17 additions & 17 deletions src/actions/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { z } from 'zod'
import { zfd } from 'zod-form-data'

import { actionClient } from '@/actions/client'
import { namestoneFetch, parentDomain } from '@/lib/namestone'
import { NamestoneProfile, NamestoneProfileSchema } from '@/types/namestone'
import { namestone, parentDomain } from '@/lib/namestone'
import { extractErrorMessage } from '@/lib/utils'
import { NamestoneProfileSchema } from '@/types/namestone'

const noSpaceString = z.string().refine((value) => !value.includes(' '))

Expand Down Expand Up @@ -42,8 +43,9 @@ export const updateName = actionClient
}

// Check if the name exists
const namesByAddress = await namestoneFetch<NamestoneProfile[]>({
path: `get-names?domain=${parentDomain}&address=${profile.address}`,
const namesByAddress = await namestone.getNames({
domain: parentDomain,
address: profile.address,
})

const nameExists = namesByAddress.find((name) => name.name === profile.name)
Expand All @@ -53,25 +55,23 @@ export const updateName = actionClient
return { error: 'Name does not exist, or you do not own this name.' }
}

// If the name exists, update it
const res = await namestoneFetch<{ success?: boolean; error?: string }>({
path: 'set-name',
method: 'POST',
body: {
try {
// If the name exists, update it
await namestone.setName({
...profile,
text_records: {
avatar: profile.avatar || '',
'com.twitter': profile.twitter || '',
'org.telegram': profile.telegram || '',
},
},
})
})

if (res.error) {
return { error: res.error }
revalidatePath('/')
return { success: true }
} catch (err) {
return {
error:
err instanceof Error ? extractErrorMessage(err) : 'Unknown error',
}
}

revalidatePath('/')

return res
})
15 changes: 4 additions & 11 deletions src/app/api/names/route.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { NextRequest, NextResponse } from 'next/server'

import { namestoneFetch, parentDomain } from '@/lib/namestone'
import { namestone, parentDomain } from '@/lib/namestone'

export async function GET(req: NextRequest) {
const searchParams = req.nextUrl.searchParams
const offset = searchParams.get('offset') || '0'
const address = searchParams.get('address')

const queryParams = new URLSearchParams({
const names = await namestone.getNames({
domain: parentDomain,
offset: offset,
})

if (address) {
queryParams.append('address', address)
}

const names = await namestoneFetch({
path: `get-names?${queryParams.toString()}`,
offset: Number(offset ?? 0),
address: address ?? undefined,
})

return NextResponse.json(names)
Expand Down
7 changes: 2 additions & 5 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@ import { XIcon } from '@/components/Icons'
import { NameManager } from '@/components/NameManager'
import { ProfileCard } from '@/components/ProfileCard'
import { Squiggle } from '@/components/Squiggle'
import { namestoneFetch, parentDomain } from '@/lib/namestone'
import { NamestoneProfile } from '@/types/namestone'
import { namestone, parentDomain } from '@/lib/namestone'

export default async function Home() {
const profiles = await namestoneFetch<NamestoneProfile[]>({
path: `get-names?domain=${parentDomain}`,
})
const profiles = await namestone.getNames({ domain: parentDomain })

return (
<main>
Expand Down
5 changes: 2 additions & 3 deletions src/components/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
'use client'

import { NameData } from 'namestone-sdk'
import Image from 'next/image'
import { useEffect, useState } from 'react'

import { NamestoneProfile } from '@/types/namestone'

import { TelegramIcon, XIcon } from './Icons'

const transparentImage =
'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg"%3E%3C/svg%3E'

export function ProfileCard({ profile }: { profile: NamestoneProfile }) {
export function ProfileCard({ profile }: { profile: NameData }) {
const [avatarUrl, setAvatarUrl] = useState<string>()
const twitter = profile.text_records?.['com.twitter']
const telegram = profile.text_records?.['org.telegram']
Expand Down
5 changes: 2 additions & 3 deletions src/hooks/useNamestone.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useQuery } from '@tanstack/react-query'
import { NameData } from 'namestone-sdk'
import { Address } from 'viem'

import { NamestoneProfile } from '@/types/namestone'

export function useNamestone(address?: Address) {
return useQuery({
queryKey: ['namestone', address],
Expand All @@ -13,7 +12,7 @@ export function useNamestone(address?: Address) {
}

const res = await fetch(`/api/names?${queryParams.toString()}`)
const json = (await res.json()) as NamestoneProfile[]
const json = (await res.json()) as NameData[]
if (address) {
return { first: json[0], all: json }
}
Expand Down
39 changes: 3 additions & 36 deletions src/lib/namestone.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,7 @@
import { NamestoneProfile } from '@/types/namestone'
import NameStone from 'namestone-sdk'

const NAMESTONE_API_KEY = process.env.NAMESTONE_API_KEY
const NAMESTONE_API_KEY = process.env.NAMESTONE_API_KEY as string

export const parentDomain = 'shefi.eth'

export type Props = {
path: string
options?: RequestInit
method?: 'GET' | 'POST'
body?: NamestoneProfile
}

export async function namestoneFetch<T>({
path,
options = {},
method = 'GET',
body,
}: Props) {
if (!NAMESTONE_API_KEY) {
throw new Error('NAMESTONE_API_KEY is not set')
}

const res = await fetch('https://namestone.xyz/api/public_v1/' + path, {
...options,
method,
headers: {
...options.headers,
Authorization: NAMESTONE_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
next: {
revalidate: 0,
},
})

const data = await res.json()
return data as T
}
export const namestone = new NameStone(NAMESTONE_API_KEY)
20 changes: 20 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,23 @@ export function cn(...inputs: ClassValue[]) {
export function truncateAddress(address: string) {
return `${address.slice(0, 6)}...${address.slice(-4)}`
}

export function extractErrorMessage(error: Error) {
const message = error.message

// Try to parse the message from the error string
const regex = /message:\s*(.+)/ // Match the message part
const match = regex.exec(message)

if (match && match[1]) {
// If a match is found, parse the JSON error object
try {
const errorObject = JSON.parse(match[1])
return errorObject.error // Return just the error message
} catch (e) {
return match[1] // Return the original message if parsing fails
}
}

return error // Fallback to the original error if no message is found
}
2 changes: 0 additions & 2 deletions src/types/namestone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ export const NamestoneProfileSchema = z.object({
text_records: z.record(z.string(), z.string()).optional(),
coin_types: z.record(z.string(), z.string()).optional(),
})

export type NamestoneProfile = z.infer<typeof NamestoneProfileSchema>
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,11 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"

namestone-sdk@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/namestone-sdk/-/namestone-sdk-0.2.8.tgz#21770fffa5c75ebbcc5d1c9ae482a23e040375a1"
integrity sha512-qFKpW4zyUxORu5kBbKoV674+jwm96qYBwH2JTSk50R3w38B6axykzrCNSnH0pgE59+89Vk5epzqkcieUA81ZaQ==

nanoid@^3.3.6, nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
Expand Down