chore: better Prettier config for easier reviews
This commit is contained in:
12
tools/api.ts
12
tools/api.ts
@ -1,17 +1,17 @@
|
||||
import axios from 'axios'
|
||||
import axios from "axios"
|
||||
|
||||
export const API_VERSION = '1.2.9'
|
||||
export const API_VERSION = "1.2.9"
|
||||
|
||||
export const API_DEFAULT_PORT = 8080
|
||||
|
||||
export const API_URL =
|
||||
process.env['NEXT_PUBLIC_API_URL'] != null
|
||||
? process.env['NEXT_PUBLIC_API_URL']
|
||||
process.env["NEXT_PUBLIC_API_URL"] != null
|
||||
? process.env["NEXT_PUBLIC_API_URL"]
|
||||
: `http://127.0.0.1:${API_DEFAULT_PORT}`
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: API_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
|
@ -1,14 +1,14 @@
|
||||
import type { AxiosInstance } from 'axios'
|
||||
import axios from 'axios'
|
||||
import type { Socket } from 'socket.io-client'
|
||||
import { io } from 'socket.io-client'
|
||||
import { isUnauthorizedError } from '@thream/socketio-jwt'
|
||||
import type { AxiosInstance } from "axios"
|
||||
import axios from "axios"
|
||||
import type { Socket } from "socket.io-client"
|
||||
import { io } from "socket.io-client"
|
||||
import { isUnauthorizedError } from "@thream/socketio-jwt"
|
||||
|
||||
import { API_URL } from '../api'
|
||||
import { cookies } from '../cookies'
|
||||
import type { Tokens } from '.'
|
||||
import { fetchRefreshToken } from './authenticationFromServerSide'
|
||||
import { clearCache } from '../cache'
|
||||
import { API_URL } from "../api"
|
||||
import { cookies } from "../cookies"
|
||||
import type { Tokens } from "."
|
||||
import { fetchRefreshToken } from "./authenticationFromServerSide"
|
||||
import { clearCache } from "../cache"
|
||||
|
||||
export class Authentication {
|
||||
public tokens: Tokens
|
||||
@ -19,18 +19,20 @@ export class Authentication {
|
||||
constructor(tokens: Tokens, disableSocketIO: boolean = false) {
|
||||
this.tokens = tokens
|
||||
this.accessTokenAge = Date.now()
|
||||
if (typeof window === 'undefined' || disableSocketIO) {
|
||||
if (typeof window === "undefined" || disableSocketIO) {
|
||||
this.socket = undefined
|
||||
} else {
|
||||
this.socket = io(API_URL, {
|
||||
auth: { token: `Bearer ${tokens.accessToken}` }
|
||||
auth: { token: `Bearer ${tokens.accessToken}` },
|
||||
})
|
||||
this.socket.on('connect', () => {
|
||||
this.socket.on("connect", () => {
|
||||
console.log(
|
||||
`Connected to socket with clientId: ${this.socket?.id ?? 'undefined'}`
|
||||
`Connected to socket with clientId: ${
|
||||
this.socket?.id ?? "undefined"
|
||||
}`,
|
||||
)
|
||||
})
|
||||
this.socket.on('connect_error', (error) => {
|
||||
this.socket.on("connect_error", (error) => {
|
||||
if (isUnauthorizedError(error)) {
|
||||
fetchRefreshToken(this.tokens.refreshToken)
|
||||
.then(({ accessToken }) => {
|
||||
@ -46,8 +48,8 @@ export class Authentication {
|
||||
this.api = axios.create({
|
||||
baseURL: API_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
this.api.interceptors.request.use(
|
||||
async (config) => {
|
||||
@ -55,7 +57,7 @@ export class Authentication {
|
||||
this.accessTokenAge + tokens.expiresIn > Date.now()
|
||||
if (!isValidAccessToken) {
|
||||
const { accessToken } = await fetchRefreshToken(
|
||||
this.tokens.refreshToken
|
||||
this.tokens.refreshToken,
|
||||
)
|
||||
this.setAccessToken(accessToken)
|
||||
}
|
||||
@ -65,7 +67,7 @@ export class Authentication {
|
||||
async (error) => {
|
||||
this.signout()
|
||||
return await Promise.reject(error)
|
||||
}
|
||||
},
|
||||
)
|
||||
this.api.interceptors.response.use(
|
||||
(response) => {
|
||||
@ -78,7 +80,7 @@ export class Authentication {
|
||||
error.config._retry = true
|
||||
try {
|
||||
const { accessToken } = await fetchRefreshToken(
|
||||
this.tokens.refreshToken
|
||||
this.tokens.refreshToken,
|
||||
)
|
||||
this.setAccessToken(accessToken)
|
||||
error.response.config.headers.Authorization = `${this.tokens.type} ${this.tokens.accessToken}`
|
||||
@ -87,7 +89,7 @@ export class Authentication {
|
||||
this.signout()
|
||||
return await Promise.reject(error)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -95,21 +97,21 @@ export class Authentication {
|
||||
this.tokens.accessToken = accessToken
|
||||
this.accessTokenAge = Date.now()
|
||||
const token = `${this.tokens.type} ${this.tokens.accessToken}`
|
||||
if (typeof this?.socket?.auth !== 'function' && this.socket != null) {
|
||||
this.socket.auth['token'] = token
|
||||
if (typeof this?.socket?.auth !== "function" && this.socket != null) {
|
||||
this.socket.auth["token"] = token
|
||||
}
|
||||
}
|
||||
|
||||
public signout(): void {
|
||||
cookies.remove('refreshToken')
|
||||
cookies.remove("refreshToken")
|
||||
clearCache()
|
||||
window.location.href = '/authentication/signin'
|
||||
window.location.href = "/authentication/signin"
|
||||
}
|
||||
|
||||
public async signoutServerSide(): Promise<void> {
|
||||
try {
|
||||
await this.api.post('/users/signout', {
|
||||
refreshToken: this.tokens.refreshToken
|
||||
await this.api.post("/users/signout", {
|
||||
refreshToken: this.tokens.refreshToken,
|
||||
})
|
||||
} catch {}
|
||||
this.signout()
|
||||
@ -117,13 +119,13 @@ export class Authentication {
|
||||
|
||||
public async signoutAllDevicesServerSide(): Promise<void> {
|
||||
try {
|
||||
await this.api.delete('/users/signout')
|
||||
await this.api.delete("/users/signout")
|
||||
} catch {}
|
||||
this.signout()
|
||||
}
|
||||
|
||||
public signin(): void {
|
||||
clearCache()
|
||||
cookies.set('refreshToken', this.tokens.refreshToken)
|
||||
cookies.set("refreshToken", this.tokens.refreshToken)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createContext, useState, useEffect, useMemo, useContext } from 'react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import setLanguage from 'next-translate/setLanguage'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import { createContext, useState, useEffect, useMemo, useContext } from "react"
|
||||
import { useTheme } from "next-themes"
|
||||
import setLanguage from "next-translate/setLanguage"
|
||||
import useTranslation from "next-translate/useTranslation"
|
||||
|
||||
import type { PagePropsWithAuthentication } from '.'
|
||||
import { Authentication } from '.'
|
||||
import type { UserCurrent } from '../../models/User'
|
||||
import type { PagePropsWithAuthentication } from "."
|
||||
import { Authentication } from "."
|
||||
import type { UserCurrent } from "../../models/User"
|
||||
|
||||
export interface AuthenticationValue {
|
||||
authentication: Authentication
|
||||
@ -15,7 +15,7 @@ export interface AuthenticationValue {
|
||||
|
||||
const defaultAuthenticationContext: AuthenticationValue = {} as any
|
||||
const AuthenticationContext = createContext<AuthenticationValue>(
|
||||
defaultAuthenticationContext
|
||||
defaultAuthenticationContext,
|
||||
)
|
||||
|
||||
export const AuthenticationProvider: React.FC<
|
||||
@ -42,15 +42,15 @@ export const AuthenticationProvider: React.FC<
|
||||
|
||||
useEffect(() => {
|
||||
authentication.api
|
||||
.put('/users/current/settings', { theme, language: lang })
|
||||
.put("/users/current/settings", { theme, language: lang })
|
||||
.then(({ data: userCurrentSettings }) => {
|
||||
setUser((oldUser) => {
|
||||
return {
|
||||
...oldUser,
|
||||
settings: {
|
||||
...oldUser.settings,
|
||||
...userCurrentSettings.settings
|
||||
}
|
||||
...userCurrentSettings.settings,
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -1,20 +1,20 @@
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios'
|
||||
import type { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||
import type { AxiosInstance, AxiosResponse } from "axios"
|
||||
import type { GetServerSideProps, GetServerSidePropsContext } from "next"
|
||||
|
||||
import { api } from '../api'
|
||||
import { Cookies } from '../cookies'
|
||||
import type { RefreshTokenResponse, Tokens } from './index'
|
||||
import { Authentication } from './Authentication'
|
||||
import type { UserCurrent } from '../../models/User'
|
||||
import { api } from "../api"
|
||||
import { Cookies } from "../cookies"
|
||||
import type { RefreshTokenResponse, Tokens } from "./index"
|
||||
import { Authentication } from "./Authentication"
|
||||
import type { UserCurrent } from "../../models/User"
|
||||
|
||||
export const fetchRefreshToken = async (
|
||||
refreshToken: string
|
||||
refreshToken: string,
|
||||
): Promise<Tokens> => {
|
||||
const { data } = await api.post<RefreshTokenResponse>(
|
||||
'/users/refresh-token',
|
||||
"/users/refresh-token",
|
||||
{
|
||||
refreshToken
|
||||
}
|
||||
refreshToken,
|
||||
},
|
||||
)
|
||||
return { ...data, refreshToken }
|
||||
}
|
||||
@ -25,33 +25,33 @@ interface AuthenticationFromServerSideOptions {
|
||||
/** allows to fetch data server side with the authenticated user, the callback should returns the data that will be transfer to the component as props */
|
||||
fetchData?: (
|
||||
context: GetServerSidePropsContext,
|
||||
api: AxiosInstance
|
||||
api: AxiosInstance,
|
||||
) => Promise<{ [key: string]: any }>
|
||||
}
|
||||
|
||||
export const authenticationFromServerSide = (
|
||||
options: AuthenticationFromServerSideOptions
|
||||
options: AuthenticationFromServerSideOptions,
|
||||
): GetServerSideProps => {
|
||||
const { shouldBeAuthenticated, fetchData } = options
|
||||
|
||||
return async (context) => {
|
||||
const cookies = new Cookies(context.req.headers.cookie)
|
||||
const refreshToken = cookies.get('refreshToken')
|
||||
const refreshToken = cookies.get("refreshToken")
|
||||
let tokens: Tokens | null = null
|
||||
if (refreshToken != null) {
|
||||
try {
|
||||
tokens = await fetchRefreshToken(refreshToken)
|
||||
} catch {
|
||||
cookies.remove('refreshToken')
|
||||
cookies.remove("refreshToken")
|
||||
}
|
||||
}
|
||||
if (!shouldBeAuthenticated) {
|
||||
if (tokens != null) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/application',
|
||||
permanent: false
|
||||
}
|
||||
destination: "/application",
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
let data: any = {}
|
||||
@ -67,9 +67,9 @@ export const authenticationFromServerSide = (
|
||||
if (tokens == null) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/authentication/signin',
|
||||
permanent: false
|
||||
}
|
||||
destination: "/authentication/signin",
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@ -78,7 +78,7 @@ export const authenticationFromServerSide = (
|
||||
const { data: currentUser } = await authentication.api.get<
|
||||
unknown,
|
||||
AxiosResponse<UserCurrent>
|
||||
>('/users/current')
|
||||
>("/users/current")
|
||||
if (fetchData != null) {
|
||||
data = await fetchData(context, authentication.api)
|
||||
}
|
||||
@ -86,11 +86,11 @@ export const authenticationFromServerSide = (
|
||||
return data
|
||||
}
|
||||
return {
|
||||
props: { authentication: { tokens, ...currentUser }, ...data }
|
||||
props: { authentication: { tokens, ...currentUser }, ...data },
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
notFound: true
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type { UserCurrent } from '../../models/User'
|
||||
import type { UserCurrent } from "../../models/User"
|
||||
|
||||
export interface RefreshTokenResponse {
|
||||
accessToken: string
|
||||
|
||||
/** how long, in milliseconds, until the accessToken expires */
|
||||
expiresIn: number
|
||||
type: 'Bearer'
|
||||
type: "Bearer"
|
||||
}
|
||||
|
||||
export interface Tokens extends RefreshTokenResponse {
|
||||
@ -21,13 +21,13 @@ export interface PagePropsWithAuthentication {
|
||||
|
||||
export const isTokens = (data: { [key: string]: any }): data is Tokens => {
|
||||
return (
|
||||
'accessToken' in data &&
|
||||
'refreshToken' in data &&
|
||||
'type' in data &&
|
||||
'expiresIn' in data
|
||||
"accessToken" in data &&
|
||||
"refreshToken" in data &&
|
||||
"type" in data &&
|
||||
"expiresIn" in data
|
||||
)
|
||||
}
|
||||
|
||||
export * from './Authentication'
|
||||
export * from './authenticationFromServerSide'
|
||||
export * from './AuthenticationContext'
|
||||
export * from "./Authentication"
|
||||
export * from "./authenticationFromServerSide"
|
||||
export * from "./AuthenticationContext"
|
||||
|
@ -1,9 +1,9 @@
|
||||
import type { PaginationItem } from '../hooks/usePagination'
|
||||
import type { PaginationItem } from "../hooks/usePagination"
|
||||
|
||||
export const GUILDS_CACHE_KEY = 'guilds' as const
|
||||
export const CHANNELS_CACHE_KEY = 'channels' as const
|
||||
export const MEMBERS_CACHE_KEY = 'members' as const
|
||||
export const MESSAGES_CACHE_KEY = 'messages' as const
|
||||
export const GUILDS_CACHE_KEY = "guilds" as const
|
||||
export const CHANNELS_CACHE_KEY = "channels" as const
|
||||
export const MEMBERS_CACHE_KEY = "members" as const
|
||||
export const MESSAGES_CACHE_KEY = "messages" as const
|
||||
|
||||
export type CacheKey =
|
||||
| typeof GUILDS_CACHE_KEY
|
||||
@ -12,7 +12,7 @@ export type CacheKey =
|
||||
| `${number}-${typeof MESSAGES_CACHE_KEY}`
|
||||
|
||||
export const getPaginationCache = <T extends PaginationItem>(
|
||||
key: CacheKey
|
||||
key: CacheKey,
|
||||
): T[] => {
|
||||
const cache = sessionStorage.getItem(key)
|
||||
if (cache != null) {
|
||||
@ -28,7 +28,7 @@ export const getPaginationCache = <T extends PaginationItem>(
|
||||
|
||||
export const savePaginationCache = <T extends PaginationItem>(
|
||||
key: CacheKey,
|
||||
data: T[]
|
||||
data: T[],
|
||||
): void => {
|
||||
sessionStorage.setItem(key, JSON.stringify(data))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import UniversalCookie from 'universal-cookie'
|
||||
import UniversalCookie from "universal-cookie"
|
||||
|
||||
export class Cookies {
|
||||
/** how long in seconds, until the cookie expires (10 years) */
|
||||
@ -12,13 +12,13 @@ export class Cookies {
|
||||
|
||||
set(name: string, value: string): void {
|
||||
this.universalCookie.set(name, value, {
|
||||
path: '/',
|
||||
maxAge: Cookies.COOKIE_MAX_AGE
|
||||
path: "/",
|
||||
maxAge: Cookies.COOKIE_MAX_AGE,
|
||||
})
|
||||
}
|
||||
|
||||
remove(name: string): void {
|
||||
this.universalCookie.remove(name, { path: '/' })
|
||||
this.universalCookie.remove(name, { path: "/" })
|
||||
}
|
||||
|
||||
get(name: string): string {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { SetItems } from '../hooks/usePagination'
|
||||
import type { CacheKey } from './cache'
|
||||
import { savePaginationCache } from './cache'
|
||||
import type { SetItems } from "../hooks/usePagination"
|
||||
import type { CacheKey } from "./cache"
|
||||
import { savePaginationCache } from "./cache"
|
||||
|
||||
export interface Item {
|
||||
id: number
|
||||
@ -8,7 +8,7 @@ export interface Item {
|
||||
}
|
||||
|
||||
export interface SocketData<T extends Item = Item> {
|
||||
action: 'create' | 'update' | 'delete'
|
||||
action: "create" | "update" | "delete"
|
||||
item: T
|
||||
}
|
||||
|
||||
@ -21,19 +21,19 @@ export interface HandleSocketDataOptions<T extends Item = Item> {
|
||||
export type SocketListener = (data: SocketData) => void
|
||||
|
||||
export const handleSocketData = <T extends Item = Item>(
|
||||
options: HandleSocketDataOptions<T>
|
||||
options: HandleSocketDataOptions<T>,
|
||||
): void => {
|
||||
const { data, setItems, cacheKey } = options
|
||||
console.log('socket.io data received: ', data)
|
||||
console.log("socket.io data received: ", data)
|
||||
|
||||
setItems((oldItems) => {
|
||||
const newItems = [...oldItems]
|
||||
switch (data.action) {
|
||||
case 'create': {
|
||||
case "create": {
|
||||
newItems.push(data.item)
|
||||
break
|
||||
}
|
||||
case 'delete': {
|
||||
case "delete": {
|
||||
const itemIndex = newItems.findIndex((item) => {
|
||||
return item.id === data.item.id
|
||||
})
|
||||
@ -42,14 +42,14 @@ export const handleSocketData = <T extends Item = Item>(
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'update': {
|
||||
case "update": {
|
||||
const itemIndex = newItems.findIndex((item) => {
|
||||
return item.id === data.item.id
|
||||
})
|
||||
if (itemIndex !== -1) {
|
||||
newItems[itemIndex] = {
|
||||
...newItems[itemIndex],
|
||||
...data.item
|
||||
...data.item,
|
||||
}
|
||||
}
|
||||
break
|
||||
|
Reference in New Issue
Block a user