Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion apps/backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

node_modules
# OS
.DS_Store

Expand Down
20 changes: 20 additions & 0 deletions apps/backend/src/clients/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import api from './client';
import { setTokens } from '../utils/token';

export const login = async (email: string, password: string) => {
const response = await api.post('/auth/login', { email, password });

const { accessToken, refreshToken } = response.data;

Check failure on line 7 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value

setTokens(accessToken, refreshToken);

Check warning on line 9 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`

Check warning on line 9 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`

return response.data;

Check failure on line 11 in apps/backend/src/clients/auth.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe return of a value of type `any`
};

export const register = async (data: any) => {
return api.post('/auth/register', data);
};

export const logout = async () => {
await api.post('/auth/logout');
};
90 changes: 90 additions & 0 deletions apps/backend/src/clients/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import axios, { AxiosError } from 'axios';
import { getAccessToken, getRefreshToken, setTokens, } from '../utils/token';
import { clearTokens } from '../utils/token';

const api = axios.create({
baseURL: process.env.VITE_API_URL || 'http://localhost:3000',
withCredentials: true,
});



api.interceptors.request.use(

Check failure on line 12 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe assignment of an `any` value
(config) => {
const token = getAccessToken();

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

return config;

Check failure on line 20 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Expected the Promise rejection reason to be an Error
},
(error) => Promise.reject(error),
);


// 🔄 RESPONSE INTERCEPTOR (Refresh Flow)
let isRefreshing = false;
let failedQueue: any[] = [];

Check failure on line 29 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe member access .reject on an `any` value

Check failure on line 29 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe call of an `any` typed value
const processQueue = (error: any, token: string | null = null) => {

Check failure on line 30 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe member access .resolve on an `any` value

Check failure on line 30 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe call of an `any` typed value
failedQueue.forEach((prom) => {
if (error) prom.reject(error);
else prom.resolve(token);
});

failedQueue = [];
};

api.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {

Check failure on line 41 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe member access ._retry on an `any` value
const originalRequest: any = error.config;

if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise((resolve, reject) => {

Check failure on line 46 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe member access .headers on an `any` value
failedQueue.push({ resolve, reject });

Check warning on line 47 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `AxiosRequestConfig<any>`
}).then((token) => {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return api(originalRequest);
});
}

originalRequest._retry = true;
isRefreshing = true;

try {
const refreshToken = getRefreshToken();

const response = await axios.post(
`${process.env.VITE_API_URL}/auth/refresh`,
{ refreshToken },
);

Check warning on line 64 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`

Check warning on line 64 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string`
const { accessToken, refreshToken: newRefreshToken } = response.data;

Check warning on line 66 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `string | null`
setTokens(accessToken, newRefreshToken);

processQueue(null, accessToken);

Check warning on line 70 in apps/backend/src/clients/client.ts

View workflow job for this annotation

GitHub Actions / build

Unsafe argument of type `any` assigned to a parameter of type `AxiosRequestConfig<any>`
originalRequest.headers['Authorization'] = 'Bearer ' + accessToken;

return api(originalRequest);
} catch (err) {
processQueue(err, null);
clearTokens();
if (typeof globalThis.window !== 'undefined') {
globalThis.window.location.href = '/login';
}
return Promise.reject(err);
} finally {
isRefreshing = false;
}
}

return Promise.reject(error);
},
);

export default api;
21 changes: 21 additions & 0 deletions apps/backend/src/services/escrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import api from "src/clients/client";

export const createEscrow = async (payload: any) => {
const response = await api.post('/escrow', payload);
return response.data;
};

export const getEscrows = async () => {
const response = await api.get('/escrow');
return response.data;
};

export const getEscrowById = async (id: string) => {
const response = await api.get(`/escrow/${id}`);
return response.data;
};

export const releaseEscrow = async (id: string) => {
const response = await api.patch(`/escrow/${id}/release`);
return response.data;
};
30 changes: 30 additions & 0 deletions apps/backend/src/utils/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const ACCESS_KEY = 'accessToken';
const REFRESH_KEY = 'refreshToken';

export const setTokens = (access: string, refresh: string) => {
if (typeof globalThis.window !== 'undefined') {
globalThis.window.localStorage.setItem(ACCESS_KEY, access);
globalThis.window.localStorage.setItem(REFRESH_KEY, refresh);
}
};

export const getAccessToken = () => {
if (typeof globalThis.window !== 'undefined') {
return globalThis.window.localStorage.getItem(ACCESS_KEY);
}
return null;
};

export const getRefreshToken = () => {
if (typeof globalThis.window !== 'undefined') {
return globalThis.window.localStorage.getItem(REFRESH_KEY);
}
return null;
};

export const clearTokens = () => {
if (typeof globalThis.window !== 'undefined') {
globalThis.window.localStorage.removeItem(ACCESS_KEY);
globalThis.window.localStorage.removeItem(REFRESH_KEY);
}
};
Loading