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 { config } from 'config';
|
||||
|
||||
const API_URL = '/api';
|
||||
|
||||
export type DirEntry = {
|
||||
name: string;
|
||||
@@ -79,7 +80,7 @@ export const useFiles = (root: string = 'home') => {
|
||||
triggerBlobDownload(blob, isDir && !name.endsWith('.zip') ? `${name}.zip` : name);
|
||||
} else {
|
||||
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, {
|
||||
method: 'POST',
|
||||
headers: { ...headers, 'Content-Type': 'application/json' },
|
||||
@@ -98,7 +99,7 @@ export const useFiles = (root: string = 'home') => {
|
||||
formData.append('file', file, name);
|
||||
}
|
||||
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) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getHeaders } from 'hooks/useClient';
|
||||
import { config } from 'config';
|
||||
|
||||
const API_URL = '/api';
|
||||
|
||||
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 token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
||||
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 {
|
||||
const headers = getHeaders();
|
||||
const token = headers['Authorization']?.replace('Bearer ', '') ?? '';
|
||||
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 {
|
||||
|
||||
@@ -12,7 +12,6 @@ export { usePopover } from './usePopover';
|
||||
export { useQueryState } from './useQueryState';
|
||||
export { useTimeout } from './useTimeout';
|
||||
export { useTimer } from './useTimer';
|
||||
export { useWebsockets } from './useWebsockets';
|
||||
export { useChatWebSocket } from './useChatWebSocket';
|
||||
export { useDataControl } from './useDataControl';
|
||||
export { useCustomSorter } from './useCustomSorter';
|
||||
|
||||
@@ -3,13 +3,12 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { useGlobal } from 'hooks/useGlobal';
|
||||
import { usePasskeys } from './usePasskeys';
|
||||
import { config } from 'config';
|
||||
|
||||
type UseAuthProps = { authUrl?: string; apiUrl?: string } | undefined;
|
||||
export type UserWithToken = User & { token: string };
|
||||
|
||||
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 [user, setUser, refreshUser] = useGlobal<UserWithToken | null>('CURRENT_USER', null);
|
||||
const authClient = useClient(authUrl);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { config } from 'config';
|
||||
import { startRegistration, startAuthentication } from '@simplewebauthn/browser';
|
||||
import type {
|
||||
PublicKeyCredentialCreationOptionsJSON,
|
||||
@@ -16,7 +15,7 @@ type PasskeyUser = {
|
||||
|
||||
export const usePasskeys = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const authClient = useClient(config.AUTH_URL);
|
||||
const authClient = useClient('/api/auth');
|
||||
|
||||
const createPasskeyCredentials = async (user: PasskeyUser) => {
|
||||
// Get registration options from server
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { config } from 'config';
|
||||
import { useGlobal } from './useGlobal';
|
||||
let theToken: string | null = null;
|
||||
|
||||
export const createClient = (baseUrl: string = config.API_URL) => {
|
||||
export const createClient = (baseUrl: string = '/api') => {
|
||||
const lsToken =
|
||||
window.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);
|
||||
useClient.config.onError = (error) => {
|
||||
setApiError(error);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
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 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