Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/client/connect/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import useAutoConnect from '../../../hooks/useAutoConnect'
import useBluetoothHRM from '../../../hooks/useBluetoothHRM'
import { useWebSocket } from '@/context/WebSocketContext'
import { getHrZoneProps } from '../../../utils/visualization'
import { API_DEBUG_RESET } from '@/constants/apiEndpoints'

// Cookie helpers
const setCookie = (name: string, value: string, days = 365) => {
Expand Down Expand Up @@ -224,7 +225,7 @@ export default function ConnectPage() {
document.cookie = 'hrm_user_age=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
document.cookie = 'hrm_device_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';

const response = await fetch('/api/debug/reset', { method: 'POST' });
const response = await fetch(API_DEBUG_RESET, { method: 'POST' });
const data = await response.json();
alert(data.message);
} catch (error) {
Expand Down
3 changes: 2 additions & 1 deletion app/client/control/components/SpotifyControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import useVolumePreference, { clampVolume } from '@/hooks/useVolumePreference'
import { useWebSocket } from '@/context/WebSocketContext'
import { SpotifyCommandMessage } from '@/types/websocket'
import { API_SPOTIFY_DEVICES } from '@/constants/apiEndpoints'

interface SpotifyDevice {
id: string
Expand Down Expand Up @@ -59,7 +60,7 @@ const SpotifyControls = () => {
setDevicesLoading(true)
setDevicesError(null)
try {
const response = await fetch('/api/spotify/devices')
const response = await fetch(API_SPOTIFY_DEVICES)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
Expand Down
3 changes: 2 additions & 1 deletion app/client/control/components/TimerControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TimerConfigMessage,
TimerModeCommandMessage,
} from '@/types/websocket'
import { API_SPOTIFY_DEVICES } from '@/constants/apiEndpoints'
import Add from '@mui/icons-material/Add'
import FitnessCenter from '@mui/icons-material/FitnessCenter'
import PlayArrow from '@mui/icons-material/PlayArrow'
Expand Down Expand Up @@ -90,7 +91,7 @@ const TimerControls = () => {
useEffect(() => {
const fetchDevices = async () => {
try {
const response = await fetch('/api/spotify/devices')
const response = await fetch(API_SPOTIFY_DEVICES)
if (!response.ok) throw new Error('Failed to fetch devices')
const devices: SpotifyDevice[] = await response.json()
setSpotifyDevices(Array.isArray(devices) ? devices : [])
Expand Down
3 changes: 2 additions & 1 deletion app/client/spotify-selection/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import VolumeControl from '../../../components/Spotify/VolumeControl' // I will
import useVolumePreference from '../../../hooks/useVolumePreference'
import { useWebSocket } from '@/context/WebSocketContext'
import { SpotifyCommandMessage } from '../../../types/websocket'
import { API_SPOTIFY_DEVICES } from '@/constants/apiEndpoints'

const PlaylistSelector = dynamic(
() => import('../../../components/Spotify/PlaylistSelector'),
Expand Down Expand Up @@ -47,7 +48,7 @@ const SpotifySelectionPage = () => {
useEffect(() => {
const fetchDevices = async () => {
try {
const response = await fetch('/api/spotify/devices')
const response = await fetch(API_SPOTIFY_DEVICES)
if (!response.ok) throw new Error('Failed to fetch devices')
const devices: SpotifyDevice[] = await response.json()
setAvailableDevices(Array.isArray(devices) ? devices : [])
Expand Down
3 changes: 2 additions & 1 deletion app/debug/spotify/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Typography from '@mui/material/Typography'
import { Session } from 'next-auth'
import { signIn, signOut, useSession } from 'next-auth/react'
import { useEffect, useState } from 'react'
import { API_DEBUG_SPOTIFY_TOKEN } from '@/constants/apiEndpoints'

interface ServerTokenStatus {
status: string
Expand All @@ -25,7 +26,7 @@ export default function SpotifyDebugPage() {
const [serverToken, setServerToken] = useState<ServerTokenStatus | null>(null)

const fetchServerToken = async () => {
const res = await fetch('/api/debug/spotify-token')
const res = await fetch(API_DEBUG_SPOTIFY_TOKEN)
if (res.ok) {
const data = await res.json()
setServerToken(data.token)
Expand Down
3 changes: 2 additions & 1 deletion components/Spotify/PlaylistSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import TextField from '@mui/material/TextField'
import Typography from '@mui/material/Typography'
import React, { useEffect, useMemo, useState } from 'react'
import { useDebounce } from '../../hooks/useDebounce'
import { API_SPOTIFY_PLAYLISTS } from '../../constants/apiEndpoints'

interface PlaylistItemProps {
playlist: Playlist
Expand Down Expand Up @@ -147,7 +148,7 @@ const PlaylistSelector: React.FC<PlaylistSelectorProps> = ({
setLoading(true)
setError(null)
try {
const response = await fetch('/api/spotify/playlists')
const response = await fetch(API_SPOTIFY_PLAYLISTS)
if (!response.ok) {
throw new Error('Failed to fetch playlists')
}
Expand Down
3 changes: 2 additions & 1 deletion components/SpotifyDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useSpotifyWebPlayback from '@/hooks/useSpotifyWebPlayback'
import useVolumePreference, { clampVolume } from '@/hooks/useVolumePreference'
import { useWebSocket } from '@/context/WebSocketContext'
import { SpotifyCommandMessage } from '@/types/websocket'
import { API_SPOTIFY_DEVICES } from '@/constants/apiEndpoints'
import VolumeUp from '@mui/icons-material/VolumeUp'
import PauseIcon from '@mui/icons-material/Pause'
import PlayArrowIcon from '@mui/icons-material/PlayArrow'
Expand Down Expand Up @@ -109,7 +110,7 @@ const SpotifyDisplay = () => {
if (spotifyLoggedIn && spotifyData.trackName) {
const fetchDevices = async () => {
try {
const response = await fetch('/api/spotify/devices')
const response = await fetch(API_SPOTIFY_DEVICES)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
Expand Down
16 changes: 16 additions & 0 deletions constants/apiEndpoints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Centralized API endpoint constants
* This file contains all API endpoint paths used throughout the application.
*/

// Spotify API endpoints
export const API_SPOTIFY_PLAYLISTS = '/api/spotify/playlists'
export const API_SPOTIFY_DEVICES = '/api/spotify/devices'
export const API_SPOTIFY_ACCESS_TOKEN = '/api/spotify/access-token'

// Debug API endpoints
export const API_DEBUG_RESET = '/api/debug/reset'
export const API_DEBUG_SPOTIFY_TOKEN = '/api/debug/spotify-token'

// Internal API endpoints
export const API_INTERNAL_TOKEN_DELIVERY = '/api/internal/token-delivery'
5 changes: 3 additions & 2 deletions hooks/useSpotifyWebPlayback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useCallback, useEffect, useState } from 'react'
import { useError } from '@/context/ErrorContext'
import { API_SPOTIFY_ACCESS_TOKEN } from '@/constants/apiEndpoints'

// Define event data types for better type safety
interface SpotifyDeviceEvent {
Expand Down Expand Up @@ -73,7 +74,7 @@ const useSpotifyWebPlayback = () => {
const getOAuthToken = useCallback(
async (cb: (token: string) => void) => {
try {
const response = await fetch('/api/spotify/access-token')
const response = await fetch(API_SPOTIFY_ACCESS_TOKEN)
if (!response.ok) {
if (response.status === 401) {
// User not logged in - this is expected, don't show as error
Expand Down Expand Up @@ -121,7 +122,7 @@ const useSpotifyWebPlayback = () => {
}

// Check if user has active session before initializing
fetch('/api/spotify/access-token')
fetch(API_SPOTIFY_ACCESS_TOKEN)
.then((response) => {
if (!response.ok) {
console.log(
Expand Down
6 changes: 5 additions & 1 deletion middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// Base path for auth routes
const API_AUTH_BASE = '/api/auth/'

export function middleware(request: NextRequest) {
// Only handle auth routes
if (!request.nextUrl.pathname.startsWith('/api/auth/')) {
if (!request.nextUrl.pathname.startsWith(API_AUTH_BASE)) {
return NextResponse.next()
}

Expand Down Expand Up @@ -43,6 +46,7 @@ export function middleware(request: NextRequest) {
}

export const config = {
// Note: matcher must be static strings for Next.js static analysis
matcher: [
'/api/auth/:path*'
]
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"pm2:stop": "pm2 stop hrm-server",
"pm2:restart": "pm2 restart hrm-server",
"pm2:delete": "pm2 delete hrm-server",
"lint": "eslint app/ components/ hooks/ lib/ services/ tests/ types/ utils/ server.ts",
"lint:fix": "eslint app/ components/ hooks/ lib/ services/ tests/ types/ utils/ server.ts --fix",
"lint": "eslint app/ components/ constants/ hooks/ lib/ services/ tests/ types/ utils/ server.ts",
"lint:fix": "eslint app/ components/ constants/ hooks/ lib/ services/ tests/ types/ utils/ server.ts --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "jest",
Expand Down
3 changes: 2 additions & 1 deletion server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { StateSnapshot } from './types/websocket.js'
import logger from './utils/logger.js'
import swaggerUi from 'swagger-ui-express'
import swaggerSpec from './lib/swagger.js'
import { API_INTERNAL_TOKEN_DELIVERY } from './constants/apiEndpoints.js'

const port: number = process.env.PORT ? +process.env.PORT : 3000 // Explicitly handle undefined and convert to number
// Allow overriding bind address via the HOST env var for flexibility in CI/containers
Expand Down Expand Up @@ -126,7 +127,7 @@ app
if (
req.method === 'POST' &&
req.url &&
req.url.includes('/api/internal/token-delivery')
req.url.includes(API_INTERNAL_TOKEN_DELIVERY)
) {
// Wait a moment for token to be written
setTimeout(async () => {
Expand Down
Loading