diff --git a/api/src/hooks.server.ts b/api/src/hooks.server.ts index 0fc1d13..1855089 100644 --- a/api/src/hooks.server.ts +++ b/api/src/hooks.server.ts @@ -1,8 +1,7 @@ -import { dev } from '$app/environment'; import type { Handle } from '@sveltejs/kit'; -import { APP_DOMAIN, DASHBOARD_DOMAIN } from '../../shared/config'; +import { APP_BASE, DASHBOARD_BASE } from '$lib/server/config'; -const domainsWithAccessToAPI = [APP_DOMAIN, DASHBOARD_DOMAIN, 'https://checkout.stripe.com']; +const domainsWithAccessToAPI = [APP_BASE, DASHBOARD_BASE, 'https://checkout.stripe.com']; const publicEndpoints = ['/', '/checkout/success']; const appendHeaders = (response: Response, origin: string | null) => { @@ -21,7 +20,7 @@ export const handle: Handle = async ({ resolve, event }) => { return response; } - if ((origin === null || !domainsWithAccessToAPI.includes(origin)) && !dev) { + if (!origin || !domainsWithAccessToAPI.includes(origin)) { console.error(`Unauthorized access attempt from origin: ${origin}`); return new Response('Unauthorised', { status: 401 }); } diff --git a/api/src/lib/server/config.ts b/api/src/lib/server/config.ts new file mode 100644 index 0000000..2a9e63d --- /dev/null +++ b/api/src/lib/server/config.ts @@ -0,0 +1,10 @@ +import { dev } from '$app/environment'; +import { + APP_DOMAIN, + APP_LOCAL_PORT, + DASHBOARD_DOMAIN, + DASHBOARD_LOCAL_PORT +} from '../../../../shared/config'; + +export const APP_BASE = dev ? `http://localhost:${APP_LOCAL_PORT}` : APP_DOMAIN; +export const DASHBOARD_BASE = dev ? `http://localhost:${DASHBOARD_LOCAL_PORT}` : DASHBOARD_DOMAIN; diff --git a/app/src/lib/global/config.ts b/app/src/lib/global/config.ts index 12da20b..5a4b670 100644 --- a/app/src/lib/global/config.ts +++ b/app/src/lib/global/config.ts @@ -1,5 +1,5 @@ import { dev } from '$app/environment'; -import { API_DOMAIN, API_LOCAL_PORT } from '../../../../shared/config'; +import { API_DOMAIN, API_LOCAL_PORT, APP_DOMAIN, APP_LOCAL_PORT } from '../../../../shared/config'; export const PUBLIC_SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL; export const PUBLIC_SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY; @@ -7,3 +7,9 @@ export const PUBLIC_SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY; export const PUBLIC_PATH_ROOTS = ['/login', '/auth', '/about', '/contact', '/privacy', '/terms']; export const API_BASE = dev ? `http://localhost:${API_LOCAL_PORT}` : API_DOMAIN; +const APP_BASE = dev ? `http://localhost:${APP_LOCAL_PORT}` : APP_DOMAIN; + +export const REQUEST_HEADER_BOILERPLATE = { + 'Content-Type': 'application/json', + origin: APP_BASE +}; diff --git a/app/src/lib/remote-functions/collections.remote.ts b/app/src/lib/remote-functions/collections.remote.ts index c67234d..2cc4f30 100644 --- a/app/src/lib/remote-functions/collections.remote.ts +++ b/app/src/lib/remote-functions/collections.remote.ts @@ -1,8 +1,7 @@ -import { form, query } from '$app/server'; -import { API_BASE } from '$lib/global/config'; +import { form } from '$app/server'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/global/config'; import * as z from 'zod'; import { requireAuth } from './auth-check'; -import { redirect } from '@sveltejs/kit'; const MakeCollectionForm = z.object({ name: z.string().min(3).max(100), @@ -23,9 +22,7 @@ export const makeCollection = form(MakeCollectionForm, async ({ name, descriptio const userId = requireAuth().id; await fetch(`${API_BASE}/collections`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ userId, name, description }) }); }); @@ -34,9 +31,7 @@ export const deleteCollection = form(DeleteCollectionForm, async ({ collectionId const userId = requireAuth().id; await fetch(`${API_BASE}/collections/${collectionId}`, { method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ userId }) }); }); @@ -46,17 +41,8 @@ export const addOrRemoveReleaseFromCollection = form( async ({ collectionId, releaseId, addOrRemove }) => { await fetch(`${API_BASE}/collections/${collectionId}`, { method: 'PATCH', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ releaseId, addOrRemove }) }); } ); - -export const getCollection = query(z.string(), async (collectionId: string) => { - const response = await fetch(`${API_BASE}/collections/${collectionId}`); - if (!response.ok) throw redirect(302, '/me/collections'); - const collection = await response.json(); - return collection; -}); diff --git a/app/src/lib/remote-functions/mixtapes.remote.ts b/app/src/lib/remote-functions/mixtapes.remote.ts index e693610..6749730 100644 --- a/app/src/lib/remote-functions/mixtapes.remote.ts +++ b/app/src/lib/remote-functions/mixtapes.remote.ts @@ -1,9 +1,7 @@ -import { form, query } from '$app/server'; -import { API_BASE } from '$lib/global/config'; +import { form } from '$app/server'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/global/config'; import * as z from 'zod'; import { requireAuth } from './auth-check'; -import type { MixtapeHydrated } from '../../../../shared/types/hydrated'; -import { redirect } from '@sveltejs/kit'; const MakeMixtapeForm = z.object({ name: z.string().min(3).max(100), @@ -15,20 +13,11 @@ const AddTrackToMixtape = z.object({ trackId: z.string() }); -export const getMixtape = query(z.string(), async (mixtapeId: string) => { - const response = await fetch(`${API_BASE}/mixtapes/${mixtapeId}`); - if (!response.ok) throw redirect(302, '/me/mixtapes'); - const mixtape: MixtapeHydrated = await response.json(); - return mixtape; -}); - export const makeMixtape = form(MakeMixtapeForm, async ({ name, description }) => { const userId = requireAuth().id; await fetch(`${API_BASE}/mixtapes`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ userId, name, description }) }); }); @@ -37,9 +26,7 @@ export const deleteMixtape = form(z.object({ mixtapeId: z.string() }), async ({ const userId = requireAuth().id; await fetch(`${API_BASE}/mixtapes/${mixtapeId}`, { method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ userId }) }); }); @@ -47,9 +34,7 @@ export const deleteMixtape = form(z.object({ mixtapeId: z.string() }), async ({ export const addTrackToMixtape = form(AddTrackToMixtape, async ({ mixtapeId, trackId }) => { await fetch(`${API_BASE}/mixtapes/${mixtapeId}`, { method: 'PATCH', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ trackId }) }); }); diff --git a/app/src/lib/remote-functions/releases.remote.ts b/app/src/lib/remote-functions/releases.remote.ts index 9ffe60c..dfaa927 100644 --- a/app/src/lib/remote-functions/releases.remote.ts +++ b/app/src/lib/remote-functions/releases.remote.ts @@ -1,10 +1,13 @@ import { query } from '$app/server'; -import { API_BASE } from '$lib/global/config'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/global/config'; import * as z from 'zod'; import type { ReleaseHydrated } from '../../../../shared/types/hydrated'; export const getHydratedRelease = query(z.string(), async (releaseId: string) => { - const response = await fetch(`${API_BASE}/releases/${releaseId}`); + const response = await fetch(`${API_BASE}/releases/${releaseId}`, { + method: 'GET', + headers: REQUEST_HEADER_BOILERPLATE + }); if (!response.ok) throw new Error('Failed to fetch release'); const release: ReleaseHydrated = await response.json(); return release; diff --git a/app/src/lib/remote-functions/user.remote.ts b/app/src/lib/remote-functions/user.remote.ts index 8e77024..d93e20c 100644 --- a/app/src/lib/remote-functions/user.remote.ts +++ b/app/src/lib/remote-functions/user.remote.ts @@ -1,5 +1,5 @@ import { form } from '$app/server'; -import { API_BASE } from '$lib/global/config'; +import { API_BASE, REQUEST_HEADER_BOILERPLATE } from '$lib/global/config'; import * as z from 'zod'; import { requireAuth } from './auth-check'; @@ -20,9 +20,7 @@ export const toggleFollowedArtist = form( await fetch(`${API_BASE}/users/${userId}/following`, { method: addOrRemove === 'remove' ? 'DELETE' : 'POST', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ artistId: artistID }) }); } @@ -33,9 +31,7 @@ export const toggleLikedTrack = form(ToggleLikedTrackForm, async ({ trackId, add await fetch(`${API_BASE}/users/${userId}/likes`, { method: addOrRemove === 'remove' ? 'DELETE' : 'POST', - headers: { - 'Content-Type': 'application/json' - }, + headers: REQUEST_HEADER_BOILERPLATE, body: JSON.stringify({ trackId }) }); }); diff --git a/app/src/routes/me/collections/[slug]/+page.svelte b/app/src/routes/me/collections/[slug]/+page.svelte index 93b415e..b034236 100644 --- a/app/src/routes/me/collections/[slug]/+page.svelte +++ b/app/src/routes/me/collections/[slug]/+page.svelte @@ -1,12 +1,25 @@ diff --git a/app/src/routes/me/collections/[slug]/+page.ts b/app/src/routes/me/collections/[slug]/+page.ts new file mode 100644 index 0000000..63eb4c9 --- /dev/null +++ b/app/src/routes/me/collections/[slug]/+page.ts @@ -0,0 +1,16 @@ +import { API_BASE } from '$lib/global/config'; +import type { CollectionHydrated } from '../../../../../../shared/types/hydrated'; + +export const load = async ({ fetch, params }) => { + const collection: CollectionHydrated = await fetch(`${API_BASE}/collections/${params.slug}`).then( + (res) => res.json() + ); + if (!collection) + return { + status: 404, + error: new Error('Not Found') + }; + return { + collection + }; +}; diff --git a/app/src/routes/me/mixtapes/[slug]/+page.svelte b/app/src/routes/me/mixtapes/[slug]/+page.svelte index 3bcfd48..bfde1c5 100644 --- a/app/src/routes/me/mixtapes/[slug]/+page.svelte +++ b/app/src/routes/me/mixtapes/[slug]/+page.svelte @@ -1,12 +1,29 @@ diff --git a/app/src/routes/me/mixtapes/[slug]/+page.ts b/app/src/routes/me/mixtapes/[slug]/+page.ts new file mode 100644 index 0000000..88bbfe8 --- /dev/null +++ b/app/src/routes/me/mixtapes/[slug]/+page.ts @@ -0,0 +1,16 @@ +import { API_BASE } from '$lib/global/config'; +import type { MixtapeHydrated } from '../../../../../../shared/types/hydrated'; + +export const load = async ({ fetch, params }) => { + const mixtape: MixtapeHydrated = await fetch(`${API_BASE}/mixtapes/${params.slug}`).then((res) => + res.json() + ); + if (!mixtape) + return { + status: 404, + error: new Error('Not Found') + }; + return { + mixtape + }; +};