Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/components/updater/updater.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let updateInfo = null

async function checkForUpdates() {
try {
const client = await getMainClient()
const client = getMainClient()
const { data } = await client.get('/extension/version')

const currentVersion = browser.runtime.getManifest().version
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/navbar/sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function SyncAccount() {

async function getAll() {
try {
const client = await getMainClient()
const client = getMainClient()
const response = await client.get<{
wallpaper: Wallpaper
theme: Theme | null
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/search/image/image-search.portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function ImageSearchPortal({
const formData = new FormData()
formData.append('image', file)

const client = await getMainClient()
const client = getMainClient()
const response = await client.post('/users/@me/upload/search', formData, {
headers: {
'Content-Type': 'multipart/form-data',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function Connections() {

try {
if (selectedPlatform.connected) {
const api = await getMainClient()
const api = getMainClient()
await api.post(`/${selectedPlatform.id}/disconnect`)

setPlatforms((prev) =>
Expand All @@ -75,7 +75,7 @@ export function Connections() {

showToast(`اتصال به ${selectedPlatform.name} قطع شد.`, 'success')
} else {
const api = await getMainClient()
const api = getMainClient()
const response = await api.post(`/${selectedPlatform.id}/connect`)

window.location.href = response.data.url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SimpleProgressRing({
cy={center}
r={radius}
fill="none"
stroke="#d1d5db"
className={'stroke-base-200'}
strokeWidth={strokeWidth}
opacity={0.3}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/layouts/widgets/network/network.layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function NetworkLayout({ enableBackground, inComboWidget }: Prop) {
const fetchNetworkData = async () => {
setIsLoading(true)
try {
const client = await getMainClient()
const client = getMainClient()
const response = await client.get('/extension/@me/ip')
const data = response.data
setNetworkInfo((prev) => ({
Expand All @@ -70,7 +70,7 @@ export function NetworkLayout({ enableBackground, inComboWidget }: Prop) {
}

try {
const client = await getMainClient()
const client = getMainClient()
const start = Date.now()
const [err, _ok] = await safeAwait<AxiosError, any>(client.get('/'))
if (err) {
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/widgets/news/components/news-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const NewsContainer = ({ customFeeds, useDefaultNews }: NewsContainerProp
}

return (
<div className={`flex flex-col gap-1`}>
<div className={`flex flex-col gap-1 overflow-y-auto`}>
{enabledFeeds.map((feed) => (
<RssFeedComponent key={feed.url} url={feed.url} sourceName={feed.name} />
))}
Expand Down
3 changes: 1 addition & 2 deletions src/layouts/widgets/news/components/news-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const NewsHeader = ({ title, onSettingsClick }: NewsHeaderProps) => {
<div className={'top-0 z-20 flex items-center justify-between w-full pb-2'}>
<div className="flex flex-col">
<div className="flex items-center gap-1.5">
<Icon name="rss" className="w-3.5 h-3.5 opacity-70" />
<p className="text-base font-medium">{title}</p>
</div>
</div>
Expand All @@ -23,7 +22,7 @@ export const NewsHeader = ({ title, onSettingsClick }: NewsHeaderProps) => {
className="h-6 w-6 p-0 flex items-center justify-center rounded-full !border-none !shadow-none"
>
<Icon
name="settings"
name="menuOption"
size={12}
className="text-content opacity-70 hover:opacity-100"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/widgets/news/news.layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const NewsLayout: React.FC<NewsLayoutProps> = ({
) : (
<WidgetContainer
background={enableBackground}
className={'flex flex-col gap-1 px-2 py-2 overflow-y-auto'}
className={'flex flex-col gap-1 px-2 py-2'}
style={{
scrollbarWidth: 'none',
}}
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/widgets/wigiArz/components/arz-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const ArzHeader = ({ title, onSettingsClick }: ArzHeaderProps) => {
className="h-6 w-6 p-0 flex items-center justify-center rounded-full !border-none !shadow-none"
>
<Icon
name="settings"
name="menuOption"
size={12}
className="text-content opacity-70 hover:opacity-100"
/>
Expand Down
106 changes: 66 additions & 40 deletions src/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,59 @@ import axios, {
import { getFromStorage, setToStorage } from '@/common/storage'
import { callEvent } from '@/common/utils/call-event'

const rawGithubApi = axios.create({
baseURL: 'https://raw.githubusercontent.com/sajjadmrx/btime-desktop/main',
})
export let API_URL = ''
export async function getMainClient(): Promise<AxiosInstance> {
let instance: AxiosInstance | undefined
export const API_URL = import.meta.env.VITE_API || 'https://api.widgetify.ir'

const token = await getFromStorage('auth_token')
API_URL = import.meta.env.VITE_API
const VERSION = browser.runtime.getManifest().version

const IGNORE_ENDPOINTS = [
'/auth/signin',
'/auth/signup',
'/auth/otp',
'/auth/otp/verify',
'/auth/oauth/google',
]

let instance: AxiosInstance | null = null
let refreshPromise: Promise<string | null> | null = null

export function getMainClient(): AxiosInstance {
if (instance) {
return instance
}

if (!API_URL) {
const urlResponse = await rawGithubApi.get('/.github/api.txt')
API_URL = urlResponse.data
throw new Error('API base URL is not defined')
}

instance = axios.create({
baseURL: API_URL,
headers: {
Authorization: token ? `Bearer ${token}` : undefined,
client: 'widgetify-extension',
version: browser.runtime.getManifest().version,
version: VERSION,
},
})

if (!instance) {
throw new Error('API base URL is not defined')
}
instance.interceptors.request.use(async (config) => {
const token = await getFromStorage('auth_token')

if (token) {
config.headers.Authorization = `Bearer ${token}`
} else {
delete config.headers.Authorization
}

return config
})

// Response interceptor to handle token refreshing
instance.interceptors.response.use(
(response: AxiosResponse) => {
return response
},
(response: AxiosResponse) => response,
async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & {
_retry?: boolean
}

const ignoreEndpoints = [
'/auth/signin',
'/auth/signup',
'/auth/otp',
'/auth/otp/verify',
'/auth/oauth/google',
]
if (
ignoreEndpoints.some((endpoint) =>
IGNORE_ENDPOINTS.some((endpoint) =>
originalRequest.url?.includes(endpoint)
)
) {
Expand All @@ -62,29 +68,49 @@ export async function getMainClient(): Promise<AxiosInstance> {

if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true

try {
const refresh_token: string | null =
await getFromStorage('refresh_token')
if (!refreshPromise) {
refreshPromise = (async () => {
const refreshToken = await getFromStorage('refresh_token')

if (!refreshToken) {
return null
}

const response = await axios.post(`${API_URL}/auth/refresh`, {
refresh_token: refreshToken,
})

if (!refresh_token) {
return
const newToken = response.data.data

if (!newToken) {
return null
}

await setToStorage('auth_token', newToken)

return newToken
})()

refreshPromise.finally(() => {
refreshPromise = null
})
}

const response = await axios.post(`${API_URL}/auth/refresh`, {
refresh_token,
})
const newToken = await refreshPromise

const newToken = response.data.data
if (newToken) {
await setToStorage('auth_token', newToken)
originalRequest.headers.Authorization = `Bearer ${newToken}`
} else {
if (!newToken) {
callEvent('auth_logout', null)
return Promise.reject(error)
}

return instance(originalRequest)
originalRequest.headers.Authorization = `Bearer ${newToken}`

return instance!(originalRequest)
} catch (_refreshError) {
callEvent('auth_logout', null)
return Promise.reject(error)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/services/config-data/config_data-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface ExtensionConfigResponse {
}

export async function getConfigData(): Promise<ExtensionConfigResponse> {
const api = await getMainClient()
const api = getMainClient()

const result = await api.get<ExtensionConfigResponse>('/extension')

Expand Down
2 changes: 1 addition & 1 deletion src/services/emoji/emoji-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface EmojiResponse {

export async function getEmojiList(): Promise<string[]> {
try {
const api = await getMainClient()
const api = getMainClient()

const emojisRes = await api.get<EmojiResponse>('/extension/emojis')

Expand Down
18 changes: 9 additions & 9 deletions src/services/hooks/auth/authService.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ interface WizardPayload {
}

async function signIn(credentials: LoginCredentials): Promise<AuthResponse> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.post<AuthResponse>('/auth/signin', credentials)

if (response.headers?.refresh_token) {
Expand All @@ -61,7 +61,7 @@ async function signIn(credentials: LoginCredentials): Promise<AuthResponse> {
}

async function signUp(credentials: SignUpCredentials): Promise<AuthResponse> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.post<AuthResponse>('/auth/signup', credentials)

if (response.headers?.refresh_token) {
Expand All @@ -72,7 +72,7 @@ async function signUp(credentials: SignUpCredentials): Promise<AuthResponse> {
}

async function updateUserProfile(formData: FormData): Promise<any> {
const api = await getMainClient()
const api = getMainClient()
const response = await api.patch('/users/@me', formData, {
headers: {
'Content-Type': 'multipart/form-data',
Expand All @@ -82,15 +82,15 @@ async function updateUserProfile(formData: FormData): Promise<any> {
}

async function updateUsername(username: string): Promise<any> {
const api = await getMainClient()
const api = getMainClient()
const response = await api.put('/users/@me/username', {
username,
})
return response.data
}

async function googleSignIn(credentials: GoogleAuthCredentials): Promise<AuthResponse> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.post<AuthResponse>('/auth/oauth/google', credentials)

if (response.headers?.refresh_token) {
Expand All @@ -101,15 +101,15 @@ async function googleSignIn(credentials: GoogleAuthCredentials): Promise<AuthRes
}

async function requestOtp(payload: OtpPayload): Promise<any> {
const client = await getMainClient()
const client = getMainClient()

const response = await client.post('/auth/otp', payload)

return response.data
}

async function verifyOtp(payload: OtpVerifyPayload): Promise<AuthResponse> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.post('/auth/otp/verify', payload)

if (response.headers?.refresh_token) {
Expand All @@ -123,13 +123,13 @@ async function getAuthState(): Promise<{
content?: string
type?: 'warning' | 'info'
}> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.get('/auth/status')
return response.data.data
}

async function setupWizard(data: WizardPayload): Promise<any> {
const client = await getMainClient()
const client = getMainClient()
const response = await client.post('/users/@me/complete-wizard', data)
return response.data
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/hooks/bookmark/add-bookmark.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const useAddBookmark = () => {
}

export async function AddBookmarkApi(input: BookmarkCreationPayload) {
const client = await getMainClient()
const client = getMainClient()

const formData = new FormData()

Expand Down
4 changes: 2 additions & 2 deletions src/services/hooks/bookmark/getBookmarks.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ export const useGetSuggestedBookmarks = () => {

export async function getBookmarks(id: string | null): Promise<FetchedBookmark[]> {
const params = id ? { id } : {}
const client = await getMainClient()
const client = getMainClient()
const { data } = await client.get<FetchedBookmark[]>('/bookmarks/@me', { params })
return data
}

export async function getSuggestedBookmarks(): Promise<BookmarkSuggestion[]> {
const client = await getMainClient()
const client = getMainClient()
const { data } = await client.get<BookmarkSuggestion[]>('/bookmarks/suggestions')
return data
}
2 changes: 1 addition & 1 deletion src/services/hooks/bookmark/remove-bookmark.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const useRemoveBookmark = () => {
return useMutation({
mutationKey: ['removeBookmark'],
mutationFn: async (bookmarkId: string) => {
const client = await getMainClient()
const client = getMainClient()
await client.delete(`/bookmarks/${bookmarkId}`)
},
})
Expand Down
Loading
Loading