Sign panel sessions and isolate test runs
Some checks failed
Deploy to Production / test (push) Failing after 29s
Some checks failed
Deploy to Production / test (push) Failing after 29s
- Replace in-memory auth sessions with signed cookies and signed OAuth state - Add auth route coverage and update panel/web server wiring - Switch test script to per-file Bun processes and clean up type checks
This commit is contained in:
@@ -19,11 +19,12 @@ export function useAuth(): AuthState & { logout: () => Promise<void> } {
|
||||
useEffect(() => {
|
||||
fetch("/auth/me", { credentials: "same-origin" })
|
||||
.then((r) => r.json())
|
||||
.then((data: { authenticated: boolean; enrolled: boolean; user?: AuthUser }) => {
|
||||
.then((data) => {
|
||||
const auth = data as { authenticated: boolean; enrolled: boolean; user?: AuthUser };
|
||||
setState({
|
||||
loading: false,
|
||||
user: data.authenticated ? data.user! : null,
|
||||
enrolled: data.enrolled ?? true,
|
||||
user: auth.authenticated ? auth.user ?? null : null,
|
||||
enrolled: auth.enrolled ?? true,
|
||||
});
|
||||
})
|
||||
.catch(() => setState({ loading: false, user: null, enrolled: true }));
|
||||
|
||||
@@ -28,11 +28,15 @@ export function useGameRoom(roomId: string, userId: string, role?: string, prefe
|
||||
const { send, subscribe, connected } = useWebSocket();
|
||||
const navigate = useNavigate();
|
||||
const navigateRef = useRef(navigate);
|
||||
const errorTimerRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const errorTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
useEffect(() => {
|
||||
navigateRef.current = navigate;
|
||||
}, [navigate]);
|
||||
useEffect(() => () => clearTimeout(errorTimerRef.current), []);
|
||||
useEffect(() => () => {
|
||||
if (errorTimerRef.current !== null) {
|
||||
clearTimeout(errorTimerRef.current);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const [state, setState] = useState<GameRoomState>({
|
||||
gameState: null,
|
||||
@@ -153,7 +157,9 @@ export function useGameRoom(roomId: string, userId: string, role?: string, prefe
|
||||
setTimeout(() => navigateRef.current("/games"), 2000);
|
||||
} else {
|
||||
setState(prev => ({ ...prev, error: msg.message }));
|
||||
clearTimeout(errorTimerRef.current);
|
||||
if (errorTimerRef.current !== null) {
|
||||
clearTimeout(errorTimerRef.current);
|
||||
}
|
||||
errorTimerRef.current = setTimeout(() => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
}, 5000);
|
||||
|
||||
@@ -44,7 +44,7 @@ function rgbToHex(r: number, g: number, b: number): string {
|
||||
function hexToRgb(hex: string): [number, number, number] | null {
|
||||
const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex.trim());
|
||||
if (!m) return null;
|
||||
return [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)];
|
||||
return [parseInt(m[1]!, 16), parseInt(m[2]!, 16), parseInt(m[3]!, 16)];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -380,7 +380,7 @@ function AiRemoveTab({ imageFile, imageSrc, onClear }: {
|
||||
</div>
|
||||
<div className="bg-card rounded-xl overflow-hidden">
|
||||
{resultUrl ? (
|
||||
<div style={BG_PRESETS[bgPreset].style}>
|
||||
<div style={BG_PRESETS[bgPreset]!.style}>
|
||||
<img src={resultUrl} className="w-full block" alt="Result" />
|
||||
</div>
|
||||
) : (
|
||||
@@ -528,7 +528,7 @@ export function BackgroundRemoval() {
|
||||
const x = Math.floor((e.clientX - rect.left) * scaleX);
|
||||
const y = Math.floor((e.clientY - rect.top) * scaleY);
|
||||
const px = canvas.getContext("2d")!.getImageData(x, y, 1, 1).data;
|
||||
setKeyColor([px[0], px[1], px[2]]);
|
||||
setKeyColor([px[0]!, px[1]!, px[2]!]);
|
||||
};
|
||||
|
||||
const handleHexInput = (v: string) => {
|
||||
@@ -832,7 +832,7 @@ export function BackgroundRemoval() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-card rounded-xl overflow-hidden">
|
||||
<div style={BG_PRESETS[bgPreset].style} className={cn("w-full", !hasResult && "hidden")}>
|
||||
<div style={BG_PRESETS[bgPreset]!.style} className={cn("w-full", !hasResult && "hidden")}>
|
||||
<canvas ref={glCanvasRef} className="w-full block" />
|
||||
</div>
|
||||
{!hasResult && (
|
||||
|
||||
@@ -468,7 +468,7 @@ export function CanvasTool() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-card rounded-xl overflow-hidden">
|
||||
<div style={BG_PRESETS[bgPreset].style} className={cn("w-full", !imageReady && "hidden")}>
|
||||
<div style={BG_PRESETS[bgPreset]!.style} className={cn("w-full", !imageReady && "hidden")}>
|
||||
<canvas ref={previewCanvasRef} className="w-full block" />
|
||||
</div>
|
||||
{!imageReady && (
|
||||
|
||||
@@ -261,7 +261,7 @@ export function CropTool() {
|
||||
let minX = width, minY = height, maxX = -1, maxY = -1;
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
if (data[(y * width + x) * 4 + 3] > 0) {
|
||||
if (data[(y * width + x) * 4 + 3]! > 0) {
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y;
|
||||
@@ -287,7 +287,7 @@ export function CropTool() {
|
||||
let minX = width, minY = height, maxX = -1, maxY = -1;
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
if (data[(y * width + x) * 4 + 3] > 0) {
|
||||
if (data[(y * width + x) * 4 + 3]! > 0) {
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y;
|
||||
|
||||
Reference in New Issue
Block a user