Remove config module dependency from frontend
- Delete unused useWebsockets.ts hook - Hardcode API URLs instead of using config module: - useClient.ts: default '/api' - useAuth.ts: '/api/auth' and '/api' - usePasskeys.ts: '/api/auth' - useImageLoader.ts: '/api' - useFiles.ts: '/api' - file-types.ts: '/api' - Remove useWebsockets export from hooks/index.ts
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useClient, getHeaders } from 'hooks/useClient';
|
import { useClient, getHeaders } from 'hooks/useClient';
|
||||||
import { config } from 'config';
|
|
||||||
|
const API_URL = '/api';
|
||||||
|
|
||||||
export type DirEntry = {
|
export type DirEntry = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -79,7 +80,7 @@ export const useFiles = (root: string = 'home') => {
|
|||||||
triggerBlobDownload(blob, isDir && !name.endsWith('.zip') ? `${name}.zip` : name);
|
triggerBlobDownload(blob, isDir && !name.endsWith('.zip') ? `${name}.zip` : name);
|
||||||
} else {
|
} else {
|
||||||
const headers = getHeaders();
|
const headers = getHeaders();
|
||||||
const url = `${config.API_URL}/${withRoot('/file-browser/download').replace(/^\//, '')}`;
|
const url = `${API_URL}/${withRoot('/file-browser/download').replace(/^\//, '')}`;
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { ...headers, 'Content-Type': 'application/json' },
|
headers: { ...headers, 'Content-Type': 'application/json' },
|
||||||
@@ -98,7 +99,7 @@ export const useFiles = (root: string = 'home') => {
|
|||||||
formData.append('file', file, name);
|
formData.append('file', file, name);
|
||||||
}
|
}
|
||||||
const authHeaders = getHeaders();
|
const authHeaders = getHeaders();
|
||||||
const url = withRoot(`${config.API_URL}/file-browser/upload?path=${encodeURIComponent(path)}`);
|
const url = withRoot(`${API_URL}/file-browser/upload?path=${encodeURIComponent(path)}`);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getHeaders } from 'hooks/useClient';
|
import { getHeaders } from 'hooks/useClient';
|
||||||
import { config } from 'config';
|
|
||||||
|
const API_URL = '/api';
|
||||||
|
|
||||||
export type FileType = 'markdown' | 'audio' | 'video' | 'image' | 'pdf' | 'code' | 'archive' | 'text';
|
export type FileType = 'markdown' | 'audio' | 'video' | 'image' | 'pdf' | 'code' | 'archive' | 'text';
|
||||||
|
|
||||||
@@ -143,14 +144,14 @@ export function getRawUrl(filePath: string, root?: string): string {
|
|||||||
const headers = getHeaders();
|
const headers = getHeaders();
|
||||||
const token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
const token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
||||||
const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : '';
|
const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : '';
|
||||||
return `${config.API_URL}/file-browser/raw?path=${encodeURIComponent(filePath)}&token=${encodeURIComponent(token)}${rootParam}`;
|
return `${API_URL}/file-browser/raw?path=${encodeURIComponent(filePath)}&token=${encodeURIComponent(token)}${rootParam}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTranscodeUrl(filePath: string, root?: string, t = '0'): string {
|
export function getTranscodeUrl(filePath: string, root?: string, t = '0'): string {
|
||||||
const headers = getHeaders();
|
const headers = getHeaders();
|
||||||
const token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
const token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
||||||
const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : '';
|
const rootParam = root && root !== 'home' ? `&root=${encodeURIComponent(root)}` : '';
|
||||||
return `${config.API_URL}/file-browser/transcode?path=${encodeURIComponent(filePath)}&t=${encodeURIComponent(t)}&token=${encodeURIComponent(token)}${rootParam}`;
|
return `${API_URL}/file-browser/transcode?path=${encodeURIComponent(filePath)}&t=${encodeURIComponent(t)}&token=${encodeURIComponent(token)}${rootParam}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArchiveBaseName(name: string): string {
|
export function getArchiveBaseName(name: string): string {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export { usePopover } from './usePopover';
|
|||||||
export { useQueryState } from './useQueryState';
|
export { useQueryState } from './useQueryState';
|
||||||
export { useTimeout } from './useTimeout';
|
export { useTimeout } from './useTimeout';
|
||||||
export { useTimer } from './useTimer';
|
export { useTimer } from './useTimer';
|
||||||
export { useWebsockets } from './useWebsockets';
|
|
||||||
export { useChatWebSocket } from './useChatWebSocket';
|
export { useChatWebSocket } from './useChatWebSocket';
|
||||||
export { useDataControl } from './useDataControl';
|
export { useDataControl } from './useDataControl';
|
||||||
export { useCustomSorter } from './useCustomSorter';
|
export { useCustomSorter } from './useCustomSorter';
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
|
|||||||
import { useClient } from 'hooks/useClient';
|
import { useClient } from 'hooks/useClient';
|
||||||
import { useGlobal } from 'hooks/useGlobal';
|
import { useGlobal } from 'hooks/useGlobal';
|
||||||
import { usePasskeys } from './usePasskeys';
|
import { usePasskeys } from './usePasskeys';
|
||||||
import { config } from 'config';
|
|
||||||
|
|
||||||
type UseAuthProps = { authUrl?: string; apiUrl?: string } | undefined;
|
type UseAuthProps = { authUrl?: string; apiUrl?: string } | undefined;
|
||||||
export type UserWithToken = User & { token: string };
|
export type UserWithToken = User & { token: string };
|
||||||
|
|
||||||
export const useAuth = (props: UseAuthProps = {}) => {
|
export const useAuth = (props: UseAuthProps = {}) => {
|
||||||
const { authUrl = config.AUTH_URL, apiUrl = config.API_URL } = props;
|
const { authUrl = '/api/auth', apiUrl = '/api' } = props;
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [user, setUser, refreshUser] = useGlobal<UserWithToken | null>('CURRENT_USER', null);
|
const [user, setUser, refreshUser] = useGlobal<UserWithToken | null>('CURRENT_USER', null);
|
||||||
const authClient = useClient(authUrl);
|
const authClient = useClient(authUrl);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { useClient } from 'hooks/useClient';
|
import { useClient } from 'hooks/useClient';
|
||||||
import { config } from 'config';
|
|
||||||
import { startRegistration, startAuthentication } from '@simplewebauthn/browser';
|
import { startRegistration, startAuthentication } from '@simplewebauthn/browser';
|
||||||
import type {
|
import type {
|
||||||
PublicKeyCredentialCreationOptionsJSON,
|
PublicKeyCredentialCreationOptionsJSON,
|
||||||
@@ -16,7 +15,7 @@ type PasskeyUser = {
|
|||||||
|
|
||||||
export const usePasskeys = () => {
|
export const usePasskeys = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const authClient = useClient(config.AUTH_URL);
|
const authClient = useClient('/api/auth');
|
||||||
|
|
||||||
const createPasskeyCredentials = async (user: PasskeyUser) => {
|
const createPasskeyCredentials = async (user: PasskeyUser) => {
|
||||||
// Get registration options from server
|
// Get registration options from server
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { config } from 'config';
|
|
||||||
import { useGlobal } from './useGlobal';
|
import { useGlobal } from './useGlobal';
|
||||||
let theToken: string | null = null;
|
let theToken: string | null = null;
|
||||||
|
|
||||||
export const createClient = (baseUrl: string = config.API_URL) => {
|
export const createClient = (baseUrl: string = '/api') => {
|
||||||
const lsToken =
|
const lsToken =
|
||||||
window.officerBearerToken ||
|
window.officerBearerToken ||
|
||||||
document.body.dataset['officerBearerToken'] ||
|
document.body.dataset['officerBearerToken'] ||
|
||||||
@@ -28,7 +27,7 @@ export const createClient = (baseUrl: string = config.API_URL) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useClient = (baseUrl: string = config.API_URL) => {
|
export const useClient = (baseUrl: string = '/api') => {
|
||||||
const [apiError, setApiError] = useGlobal<ErrorDetails | null>('API_ERROR', null);
|
const [apiError, setApiError] = useGlobal<ErrorDetails | null>('API_ERROR', null);
|
||||||
useClient.config.onError = (error) => {
|
useClient.config.onError = (error) => {
|
||||||
setApiError(error);
|
setApiError(error);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { useClient } from 'hooks/useClient';
|
import { useClient } from 'hooks/useClient';
|
||||||
import { config } from 'config';
|
|
||||||
|
|
||||||
export const useImageLoader = (baseUrl: string = config.FILES_URL) => {
|
export const useImageLoader = (baseUrl: string = '/api') => {
|
||||||
const listContainer = useRef<HTMLDivElement>(null);
|
const listContainer = useRef<HTMLDivElement>(null);
|
||||||
const filesClient = useClient(baseUrl);
|
const filesClient = useClient(baseUrl);
|
||||||
|
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
||||||
import { config } from 'config';
|
|
||||||
import type { WebSocketMessage } from './types';
|
|
||||||
|
|
||||||
type MessageHandler = (data: WebSocketMessage) => void;
|
|
||||||
|
|
||||||
export const useWebsockets = (onMessage?: MessageHandler) => {
|
|
||||||
const [isOnline, setOnline] = useState(false);
|
|
||||||
const [userCount, setUserCount] = useState(0);
|
|
||||||
|
|
||||||
const socketRef = useRef<WebSocket | null>(null);
|
|
||||||
const retryRef = useRef(0);
|
|
||||||
const retryTimeoutRef = useRef<number | null>(null);
|
|
||||||
const isCleaningUpRef = useRef(false);
|
|
||||||
|
|
||||||
const connectSocket = useCallback(() => {
|
|
||||||
if (isCleaningUpRef.current) return;
|
|
||||||
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) return;
|
|
||||||
|
|
||||||
const socket = new WebSocket(config.WS_URL);
|
|
||||||
socketRef.current = socket;
|
|
||||||
|
|
||||||
socket.addEventListener('open', () => {
|
|
||||||
setOnline(true);
|
|
||||||
retryRef.current = 0;
|
|
||||||
console.log('🟢 Connected to', config.WS_URL);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener('message', (event) => {
|
|
||||||
try {
|
|
||||||
let data: WebSocketMessage;
|
|
||||||
|
|
||||||
if (event.data instanceof ArrayBuffer) {
|
|
||||||
const text = new TextDecoder().decode(event.data);
|
|
||||||
data = JSON.parse(text) as WebSocketMessage;
|
|
||||||
} else if (typeof event.data === 'string') {
|
|
||||||
data = JSON.parse(event.data) as WebSocketMessage;
|
|
||||||
} else {
|
|
||||||
console.warn('⚠️ Unknown WS message type:', typeof event.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
data &&
|
|
||||||
typeof data === 'object' &&
|
|
||||||
'type' in data &&
|
|
||||||
data.type === 'users' &&
|
|
||||||
'count' in data &&
|
|
||||||
typeof data.count === 'number'
|
|
||||||
) {
|
|
||||||
console.log('👥 Users online:', data.count);
|
|
||||||
setUserCount(data.count);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMessage?.(data);
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('⚠️ Failed to parse WS message:', event.data, err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener('close', () => {
|
|
||||||
if (isCleaningUpRef.current) return;
|
|
||||||
|
|
||||||
setOnline(false);
|
|
||||||
console.log('🔴 Disconnected');
|
|
||||||
|
|
||||||
const retry = (retryRef.current ?? 0) + 1;
|
|
||||||
retryRef.current = retry;
|
|
||||||
const delay = Math.min(5000, 300 * retry);
|
|
||||||
retryTimeoutRef.current = window.setTimeout(connectSocket, delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener('error', (err) => {
|
|
||||||
console.error('⚠️ WebSocket error', err);
|
|
||||||
socket.close();
|
|
||||||
});
|
|
||||||
}, [onMessage]);
|
|
||||||
|
|
||||||
const send = useCallback((data: string | Record<string, unknown>) => {
|
|
||||||
const socket = socketRef.current;
|
|
||||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
||||||
socket.send(typeof data === 'string' ? data : JSON.stringify(data));
|
|
||||||
} else {
|
|
||||||
console.warn('Cannot send message, socket not ready');
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
isCleaningUpRef.current = false;
|
|
||||||
connectSocket();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isCleaningUpRef.current = true;
|
|
||||||
|
|
||||||
if (retryTimeoutRef.current !== null) {
|
|
||||||
clearTimeout(retryTimeoutRef.current);
|
|
||||||
retryTimeoutRef.current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socketRef.current) {
|
|
||||||
socketRef.current.close();
|
|
||||||
socketRef.current = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [connectSocket]);
|
|
||||||
|
|
||||||
return { isOnline, userCount, send };
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UseWebsocketsReturn = ReturnType<typeof useWebsockets>;
|
|
||||||
Reference in New Issue
Block a user