fix spa routing
Some checks failed
ci/woodpecker/push/build Pipeline failed

This commit is contained in:
Jake Walker 2025-02-05 23:29:48 +00:00
parent 54bf779a55
commit f0b4a38775
No known key found for this signature in database
5 changed files with 70 additions and 11 deletions

View file

@ -41,3 +41,5 @@ tasks:
deps: [frontend:generate]
cmds:
- pnpm run build
- rm -rf ../dist
- mv dist ../dist

View file

@ -2,8 +2,8 @@
import type { Options } from '@hey-api/client-fetch';
import { queryOptions, type MutationOptions } from '@tanstack/solid-query';
import type { GetAppConfigData, ReadUserData, ReadPodcastsData, CreatePodcastData, CreatePodcastError, CreatePodcastResponse, DeletePodcastData, DeletePodcastError, ReadPodcastData, UpdatePodcastData, UpdatePodcastError, UpdatePodcastResponse, UpdatePodcastImageData, UpdatePodcastImageError, UpdatePodcastImageResponse, ReadEpisodesData, AdminUploadEpisodeData, AdminUploadEpisodeError, DeleteEpisodeData, DeleteEpisodeError, ReadEpisodeData, UpdateEpisodeData, UpdateEpisodeError, UpdateEpisodeResponse, EpisodeAdditionalUploadData, EpisodeAdditionalUploadError, EpisodeAdditionalUploadResponse, GetPodcastFeedData, GetEpisodeOrCoverData } from '../types.gen';
import { getAppConfig, readUser, readPodcasts, createPodcast, deletePodcast, readPodcast, updatePodcast, updatePodcastImage, readEpisodes, adminUploadEpisode, deleteEpisode, readEpisode, updateEpisode, episodeAdditionalUpload, getPodcastFeed, getEpisodeOrCover, client } from '../sdk.gen';
import type { GetAppConfigData, ReadUserData, ReadPodcastsData, CreatePodcastData, CreatePodcastError, CreatePodcastResponse, DeletePodcastData, DeletePodcastError, ReadPodcastData, UpdatePodcastData, UpdatePodcastError, UpdatePodcastResponse, UpdatePodcastImageData, UpdatePodcastImageError, UpdatePodcastImageResponse, ReadEpisodesData, AdminUploadEpisodeData, AdminUploadEpisodeError, DeleteEpisodeData, DeleteEpisodeError, ReadEpisodeData, UpdateEpisodeData, UpdateEpisodeError, UpdateEpisodeResponse, EpisodeAdditionalUploadData, EpisodeAdditionalUploadError, EpisodeAdditionalUploadResponse, GetPodcastFeedData, GetEpisodeOrCoverData, ServeAppData } from '../types.gen';
import { getAppConfig, readUser, readPodcasts, createPodcast, deletePodcast, readPodcast, updatePodcast, updatePodcastImage, readEpisodes, adminUploadEpisode, deleteEpisode, readEpisode, updateEpisode, episodeAdditionalUpload, getPodcastFeed, getEpisodeOrCover, serveApp, client } from '../sdk.gen';
type QueryKey<TOptions extends Options> = [
Pick<TOptions, 'baseUrl' | 'body' | 'headers' | 'path' | 'query'> & {
@ -370,4 +370,23 @@ export const getEpisodeOrCoverOptions = (options: Options<GetEpisodeOrCoverData>
},
queryKey: getEpisodeOrCoverQueryKey(options)
});
};
export const serveAppQueryKey = (options: Options<ServeAppData>) => [
createQueryKey('serveApp', options)
];
export const serveAppOptions = (options: Options<ServeAppData>) => {
return queryOptions({
queryFn: async ({ queryKey, signal }) => {
const { data } = await serveApp({
...options,
...queryKey[0],
signal,
throwOnError: true
});
return data;
},
queryKey: serveAppQueryKey(options)
});
};

View file

@ -1,7 +1,7 @@
// This file is auto-generated by @hey-api/openapi-ts
import { createClient, createConfig, type Options, formDataBodySerializer } from '@hey-api/client-fetch';
import type { GetAppConfigData, GetAppConfigResponse, ReadUserData, ReadUserResponse, ReadPodcastsData, ReadPodcastsResponse, CreatePodcastData, CreatePodcastResponse, CreatePodcastError, DeletePodcastData, DeletePodcastError, ReadPodcastData, ReadPodcastResponse, ReadPodcastError, UpdatePodcastData, UpdatePodcastResponse, UpdatePodcastError, UpdatePodcastImageData, UpdatePodcastImageResponse, UpdatePodcastImageError, ReadEpisodesData, ReadEpisodesResponse, ReadEpisodesError, AdminUploadEpisodeData, AdminUploadEpisodeError, DeleteEpisodeData, DeleteEpisodeError, ReadEpisodeData, ReadEpisodeResponse, ReadEpisodeError, UpdateEpisodeData, UpdateEpisodeResponse, UpdateEpisodeError, EpisodeAdditionalUploadData, EpisodeAdditionalUploadResponse, EpisodeAdditionalUploadError, GetPodcastFeedData, GetPodcastFeedError, GetEpisodeOrCoverData, GetEpisodeOrCoverError } from './types.gen';
import type { GetAppConfigData, GetAppConfigResponse, ReadUserData, ReadUserResponse, ReadPodcastsData, ReadPodcastsResponse, CreatePodcastData, CreatePodcastResponse, CreatePodcastError, DeletePodcastData, DeletePodcastError, ReadPodcastData, ReadPodcastResponse, ReadPodcastError, UpdatePodcastData, UpdatePodcastResponse, UpdatePodcastError, UpdatePodcastImageData, UpdatePodcastImageResponse, UpdatePodcastImageError, ReadEpisodesData, ReadEpisodesResponse, ReadEpisodesError, AdminUploadEpisodeData, AdminUploadEpisodeError, DeleteEpisodeData, DeleteEpisodeError, ReadEpisodeData, ReadEpisodeResponse, ReadEpisodeError, UpdateEpisodeData, UpdateEpisodeResponse, UpdateEpisodeError, EpisodeAdditionalUploadData, EpisodeAdditionalUploadResponse, EpisodeAdditionalUploadError, GetPodcastFeedData, GetPodcastFeedError, GetEpisodeOrCoverData, GetEpisodeOrCoverError, ServeAppData, ServeAppError } from './types.gen';
export const client = createClient(createConfig());
@ -187,7 +187,17 @@ export const getPodcastFeed = <ThrowOnError extends boolean = false>(options: Op
*/
export const getEpisodeOrCover = <ThrowOnError extends boolean = false>(options: Options<GetEpisodeOrCoverData, ThrowOnError>) => {
return (options?.client ?? client).get<unknown, GetEpisodeOrCoverError, ThrowOnError>({
url: '/{podcast_id}/{filename}',
url: '/files/{podcast_id}/{filename}',
...options
});
};
/**
* Serve App
*/
export const serveApp = <ThrowOnError extends boolean = false>(options: Options<ServeAppData, ThrowOnError>) => {
return (options?.client ?? client).get<unknown, ServeAppError, ThrowOnError>({
url: '/{full_path}',
...options
});
};

View file

@ -444,7 +444,7 @@ export type GetEpisodeOrCoverData = {
filename: string;
};
query?: never;
url: '/{podcast_id}/{filename}';
url: '/files/{podcast_id}/{filename}';
};
export type GetEpisodeOrCoverErrors = {
@ -461,4 +461,29 @@ export type GetEpisodeOrCoverResponses = {
* Successful Response
*/
200: unknown;
};
export type ServeAppData = {
body?: never;
path: {
full_path: string;
};
query?: never;
url: '/{full_path}';
};
export type ServeAppErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type ServeAppError = ServeAppErrors[keyof ServeAppErrors];
export type ServeAppResponses = {
/**
* Successful Response
*/
200: unknown;
};

View file

@ -429,7 +429,7 @@ def get_podcast_feed(session: SessionDep, request: Request, podcast_id: str):
description=podcast.description,
image=urllib.parse.urljoin(
str(request.base_url),
f"/{podcast.id}/{podcast.image_filename}",
f"/files/{podcast.id}/{podcast.image_filename}",
)
if podcast.image_filename is not None
else None,
@ -446,7 +446,7 @@ def get_podcast_feed(session: SessionDep, request: Request, podcast_id: str):
publication_date=episode.publish_date.astimezone(tz=timezone.utc),
media=podgen.Media(
urllib.parse.urljoin(
str(request.base_url), f"{podcast.id}/{episode.id}.m4a"
str(request.base_url), f"/files/{podcast.id}/{episode.id}.m4a"
),
episode.file_size,
duration=timedelta(seconds=episode.duration)
@ -460,7 +460,7 @@ def get_podcast_feed(session: SessionDep, request: Request, podcast_id: str):
return Response(content=feed.rss_str(), media_type="application/xml")
@app.get("/{podcast_id}/{filename}")
@app.get("/files/{podcast_id}/{filename}")
def get_episode_or_cover(session: SessionDep, podcast_id: str, filename: str):
podcast = session.exec(
select(models.Podcast).where(models.Podcast.id == podcast_id)
@ -492,9 +492,12 @@ def get_episode_or_cover(session: SessionDep, podcast_id: str, filename: str):
return HTTPException(status_code=404, detail="File not found")
@app.get("/{catchall:path}")
async def serve_app(catchall: str):
return FileResponse("dist/index.html")
@app.get("/{full_path:path}")
async def serve_app(full_path: str):
if not full_path.startswith("api/"):
return FileResponse("dist/index.html")
return HTTPException(status_code=404, detail="Not found")
use_route_names_as_operation_ids(app)