I'm using nodejs express. CORS credentials: true and fetch include true are causing so much issues in different devices, I want an approach that doesn't have any issues on any devices.

server.ts:
import express from 'express';
import morgan from 'morgan';
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
import cors from 'cors';

import { errorHandler } from './middleware/errorHandler';
import categoryRoutes from './routes/categoryRoutes';
import subcategoryRoutes from './routes/subcategoryRoutes';
import productRoutes from "./routes/productRoutes";
import userRoutes from "./routes/userRoutes";
import counterRoutes from "./routes/counterRoutes";
import addressRoutes from "./routes/addressRoutes";
import couponRoutes from "./routes/couponRoutes";
import cartRoutes from "./routes/cartRoutes";
import {isAdmin} from "./middleware/authMiddleware";

dotenv.config();

const app = express();


app.use(cors({
    credentials: true,
    origin: "https://admin.naayiq.com"
}));


app.use(express.json());
app.use(cookieParser());
app.use(morgan('dev'));

app.set('trust proxy', 1);

// Routes
app.use('/user', userRoutes);
app.use('/counter', isAdmin, counterRoutes)
app.use('/categories', categoryRoutes);
app.use('/subcategories', subcategoryRoutes);
app.use('/products', productRoutes);
app.use('/addresses', isAdmin, addressRoutes);
app.use('/coupons', isAdmin, couponRoutes);
app.use('/cart', isAdmin, cartRoutes);
app.use(errorHandler);

if (process.env.NODE_ENV !== 'production') {
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
        console.log(`Server running on port ${PORT}`);
    });
}

export default app;
productRoutes.ts:
import express from "express";
import { getProducts, getProductById, createProduct, updateProduct, deleteProduct } from "../controllers/productController";
import {isAdmin} from "../middleware/authMiddleware";

const router = express.Router();

router.get("/", getProducts);
router.get("/:id", getProductById);
router.post("/", isAdmin, createProduct);
router.put("/:id", isAdmin, updateProduct);
router.delete("/:id", isAdmin, deleteProduct);

export default router;
userRoutes.ts:
import express from 'express';
import { body } from 'express-validator';
import * as userController from '../controllers/userController';
import { validateRequest } from '../middleware/validateRequest';
import { isAdmin } from '../middleware/authMiddleware';

const router = express.Router();

// Existing routes
router.post(
    '/signup',
    [
        body('name').trim().notEmpty().withMessage('Name is required'),
        body('email').isEmail().normalizeEmail().withMessage('Valid email is required'),
        body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters long'),
    ],
    validateRequest,
    userController.signup
);

router.post(
    '/login',
    [
        body('email').isEmail().normalizeEmail(),
        body('password').notEmpty(),
        body('rememberMe').isBoolean().optional(),
    ],
    validateRequest,
    userController.login
);

router.post('/logout', userController.logout);
router.get('/check-auth', userController.checkAuth);

// New CRUD routes (admin only)
router.get('/users', isAdmin, userController.getAllUsers);
router.get('/users/:id', isAdmin, userController.getUserById);
router.post(
    '/users',
    isAdmin,
    [
        body('name').trim().notEmpty().withMessage('Name is required'),
        body('email').isEmail().normalizeEmail().withMessage('Valid email is required'),
        body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters long'),
        body('role').isIn(['user', 'admin', 'superadmin']).withMessage('Invalid role'),
    ],
    validateRequest,
    userController.createUser
);
router.put(
    '/users/:id',
    isAdmin,
    [
        body('name').trim().notEmpty().withMessage('Name is required').optional(),
        body('email').isEmail().normalizeEmail().withMessage('Valid email is required').optional(),
        body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters long').optional(),
        body('role').isIn(['user', 'admin', 'superadmin']).withMessage('Invalid role').optional(),
        body('is_active').isBoolean().withMessage('is_active must be a boolean').optional(),
    ],
    validateRequest,
    userController.updateUser
);
router.delete('/users/:id', isAdmin, userController.deleteUser);

export default router;
userController.ts:
import { Request, Response } from 'express';
import * as userModel from '../models/userModel';
import jwt from "jsonwebtoken";

export const signup = async (req: Request, res: Response): Promise<void> => {
    try {
        const { name, email, password, phone } = req.body;
        const user = await userModel.createUser(name, email, password, 'user', phone);

        // @ts-ignore
        req.session.userId = user.user_id;
        res.status(201).json({
            message: 'User created successfully',
            userId: user.user_id,
            name: user.name,
            role: 'user',
            phone_number: user.phone_number
        });
    } catch (error: any) {
        if (error.code === '23505') {
            res.status(409).json({ message: 'Email already exists' });
        } else {
            res.status(500).json({ message: 'Internal server error' });
        }
    }
};

export const login = async (req: Request, res: Response): Promise<void> => {
    try {
        const { email, password, rememberMe } = req.body;
        const user = await userModel.findUserByEmail(email);
        if (!user || !await userModel.comparePassword(password, user.password)) {
            res.status(401).json({ message: 'Invalid credentials' });
            return;
        }
        if (!user.is_active) {
            res.status(403).json({ message: 'Inactive account' });
            return;
        }

        const expiresIn = '30d'
        const token = jwt.sign(
            { userId: user.user_id, name: user.name, active: user.is_active, email: user.email, role: user.role || 'user', phone_number: user.phone_number },
            process.env.JWT_SECRET!,
            { expiresIn }
        );

        if (rememberMe) {
            // Set a persistent cookie for 30 days
            res.cookie('accessToken', token, {
                httpOnly: true,
                secure: false,
                sameSite: 'lax',
                maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
            });
        } else {
            // Set a session cookie (expires when browser is closed)
            res.cookie('accessToken', token, {
                httpOnly: true,
                secure: false,
                sameSite: 'lax'
            });
        }

        res.status(200).json({ message: 'Login successful', token: token, phone_number: user.phone_number });
    } catch (error) {
        console.error('Error in user login:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

export const logout = (req: Request, res: Response): void => {
    res.clearCookie('accessToken', {
        httpOnly: true,
        secure: true,
        sameSite: 'none'
    });
    res.json({ message: 'Logged out successfully' });
};

export const checkAuth = (req: Request, res: Response): void => {
    const token = req.cookies.accessToken;
    if (token) {
        try {
            const decoded = jwt.verify(token, process.env.JWT_SECRET!) as jwt.JwtPayload;
            res.json({
                isAuthenticated: true,
                userId: decoded.userId,
                name: decoded.name,
                active: decoded.active,
                email: decoded.email,
                role: decoded.role
            });
        } catch (error) {
            res.json({ isAuthenticated: false });
        }
    } else {
        res.json({ isAuthenticated: false });
    }
};

export const getAllUsers = async (req: Request, res: Response): Promise<void> => {
    try {
        const users = await userModel.findAllUsers();
        res.status(200).json(users.map(user => ({
            userId: user.user_id,
            name: user.name,
            email: user.email,
            role: user.role,
            is_active: user.is_active,
            phone_number: user.phone_number
        })));
    } catch (error) {
        console.error('Error fetching all users:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

export const getUserById = async (req: Request, res: Response): Promise<void> => {
    try {
        const userId = parseInt(req.params.id);
        const user = await userModel.findUserById(userId);
        if (!user) {
            res.status(404).json({ message: 'User not found' });
            return;
        }
        res.status(200).json({
            userId: user.user_id,
            name: user.name,
            email: user.email,
            role: user.role,
            is_active: user.is_active,
            phone_number: user.phone_number
        });
    } catch (error) {
        console.error('Error fetching user by ID:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

export const createUser = async (req: Request, res: Response): Promise<void> => {
    try {
        const { name, email, password, role, phone_number } = req.body;
        const newUser = await userModel.createUser(name, email, password, role, phone_number);
        res.status(201).json({
            message: 'User created successfully',
            userId: newUser.user_id,
            name: newUser.name,
            email: newUser.email,
            role: newUser.role,
            phone_number: newUser.phone_number
        });
    } catch (error: any) {
        if (error.code === '23505') {
            res.status(409).json({ message: 'Email already exists' });
        } else {
            console.error('Error creating user:', error);
            res.status(500).json({ message: 'Internal server error' });
        }
    }
};

export const updateUser = async (req: Request, res: Response): Promise<void> => {
    try {
        const userId = parseInt(req.params.id);
        const { name, email, password, role, is_active, phone_number } = req.body;
        const updatedUser = await userModel.updateUser(userId, { name, email, password, role, is_active, phone_number });
        if (!updatedUser) {
            res.status(404).json({ message: 'User not found' });
            return;
        }
        res.status(200).json({
            message: 'User updated successfully',
            userId: updatedUser.user_id,
            name: updatedUser.name,
            email: updatedUser.email,
            role: updatedUser.role,
            is_active: updatedUser.is_active,
            phone_number: updatedUser.phone_number
        });
    } catch (error) {
        console.error('Error updating user:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

export const deleteUser = async (req: Request, res: Response): Promise<void> => {
    try {
        const userId = parseInt(req.params.id);
        const deleted = await userModel.deleteUser(userId);
        if (!deleted) {
            res.status(404).json({ message: 'User not found' });
            return;
        }
        res.status(200).json({ message: 'User deleted successfully' });
    } catch (error) {
        console.error('Error deleting user:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
};

userModel.ts:
import bcrypt from 'bcrypt';
import { query } from '../config/database';

export interface User {
    user_id: number;
    name: string;
    email: string;
    password: string;
    phone_number?: string | null;
    dob?: Date | null;
    created_at?: Date;
    last_login?: Date | null;
    is_active: boolean;
    role: 'admin' | 'superadmin' | 'user';
}


export const createUser = async (
    name: string,
    email: string,
    password: string,
    role: 'admin' | 'superadmin' | 'user' = 'user',
    phone_number?: string
): Promise<Omit<User, "password">> => {
    const hashedPassword = await bcrypt.hash(password, 10);
    const result = await query(
        'INSERT INTO users (name, email, password, role, phone_number) VALUES ($1, $2, $3, $4, $5) RETURNING user_id, name, email, role, phone_number',
        [name, email, hashedPassword, role, phone_number]
    );
    return result.rows[0];
};


export const findUserById = async (userId: number): Promise<User | null> => {
    const result = await query('SELECT user_id, name, email, role, is_active, phone_number FROM users WHERE user_id = $1', [userId]);
    return result.rows[0] || null;
};


export const findUserByEmail = async (email: string): Promise<User | null> => {
    const result = await query('SELECT * FROM users WHERE email = $1', [email]);
    return result.rows[0] || null;
};


export const comparePassword = async (password: string, hashedPassword: string): Promise<boolean> => {
    return bcrypt.compare(password, hashedPassword);
};

export const findAllUsers = async (): Promise<Omit<User, "password">[]> => {
    const result = await query('SELECT user_id, name, email, role, is_active, phone_number FROM users');
    return result.rows;
};


export const updateUser = async (userId: number, updates: Partial<User>): Promise<User | null> => {
    const { name, email, password, role, is_active, phone_number } = updates;
    let hashedPassword = password ? await bcrypt.hash(password, 10) : undefined;

    const setClause = Object.entries({ name, email, password: hashedPassword, role, is_active, phone_number })
        .filter(([_, value]) => value !== undefined)
        .map(([key], index) => `${key} = $${index + 2}`)
        .join(', ');

    const values = [userId, ...Object.values({ name, email, password: hashedPassword, role, is_active, phone_number }).filter(value => value !== undefined)];

    const result = await query(
        `UPDATE users SET ${setClause} WHERE user_id = $1 RETURNING user_id, name, email, role, is_active, phone_number`,
        values
    );

    return result.rows[0] || null;
};


export const deleteUser = async (userId: number): Promise<boolean> => {
    const result = await query('DELETE FROM users WHERE user_id = $1 RETURNING user_id', [userId]);
    return result.rowCount > 0;
};
config/database.ts:
import { Pool, QueryResult, QueryResultRow } from 'pg';
import dotenv from 'dotenv';

dotenv.config();

const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
    throw new Error('DATABASE_URL is not set in the environment');
}

const pool = new Pool({
    connectionString,
    max: 10,
    idleTimeoutMillis: 120000,
    connectionTimeoutMillis: 10000,
});

pool.on('error', (err) => {
    console.error('Unexpected error on idle client', err);
    process.exit(-1);
});

export async function query<T extends QueryResultRow = any>(text: string, params?: any[]): Promise<QueryResult<T>> {
    const client = await pool.connect();
    try {
        return await client.query(text, params);
    } catch (error) {
        console.error('Error executing query', { text, error });
        throw error;
    } finally {
        client.release();
    }
}

export function getClient() {
    return pool.connect();
}