Split the server API module into client, guards, form fields and action helpers
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { fail, type RequestEvent } from '@sveltejs/kit';
|
||||
import { apiFor, type ApiClient } from '$lib/server/api';
|
||||
|
||||
export interface ActionContext {
|
||||
api: ApiClient;
|
||||
form: FormData;
|
||||
params: Record<string, string>;
|
||||
locals: App.Locals;
|
||||
url: URL;
|
||||
}
|
||||
|
||||
export function authedAction<R>(
|
||||
handler: (context: ActionContext) => R | Promise<R>,
|
||||
unauthorizedMessage = 'Inicia sesión.'
|
||||
) {
|
||||
return async (event: RequestEvent) => {
|
||||
if (!event.locals.accessToken) return fail(401, { message: unauthorizedMessage });
|
||||
const form = await event.request.formData();
|
||||
return handler({
|
||||
api: apiFor(event),
|
||||
form,
|
||||
params: event.params as Record<string, string>,
|
||||
locals: event.locals,
|
||||
url: event.url
|
||||
});
|
||||
};
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { authedAction } from '$lib/server/api';
|
||||
import { authedAction } from '$lib/server/actions/authedAction';
|
||||
|
||||
const setFollowing = (follow: boolean) =>
|
||||
authedAction(async ({ api, params }) => {
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { authedAction, formString } from '$lib/server/api';
|
||||
import { formString } from '$lib/server/forms/fields';
|
||||
import { authedAction } from '$lib/server/actions/authedAction';
|
||||
|
||||
export const addTrackAction = authedAction(async ({ api, form, params }) => {
|
||||
const playlistId = formString(form, 'playlistId') || (params.id ?? '');
|
||||
@@ -1,7 +1,6 @@
|
||||
import createClient from 'openapi-fetch';
|
||||
import { error, fail, redirect, type ActionFailure, type RequestEvent } from '@sveltejs/kit';
|
||||
import { error, fail, type ActionFailure, type RequestEvent } from '@sveltejs/kit';
|
||||
import type { paths } from '$lib/api/schema';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
import { apiConfig } from '$lib/server/config';
|
||||
|
||||
interface ApiClientOptions {
|
||||
@@ -23,59 +22,6 @@ export function apiFor({ fetch, locals }: Pick<RequestEvent, 'fetch' | 'locals'>
|
||||
return createApiClient({ fetch, accessToken: locals.accessToken ?? undefined });
|
||||
}
|
||||
|
||||
export function loginRedirect(url: URL): never {
|
||||
redirect(302, `/auth?returnTo=${encodeURIComponent(url.pathname + url.search)}`);
|
||||
}
|
||||
|
||||
export function requireUser(locals: App.Locals, url: URL): SessionUser {
|
||||
if (!locals.user) loginRedirect(url);
|
||||
return locals.user;
|
||||
}
|
||||
|
||||
export function optionalUser(
|
||||
locals: App.Locals,
|
||||
url: URL,
|
||||
allowAnonymousListening: boolean
|
||||
): SessionUser | null {
|
||||
if (locals.user) return locals.user;
|
||||
if (!allowAnonymousListening) loginRedirect(url);
|
||||
return null;
|
||||
}
|
||||
|
||||
export function formString(form: FormData, key: string): string {
|
||||
return String(form.get(key) ?? '');
|
||||
}
|
||||
|
||||
export function formFile(form: FormData, key: string): File | null {
|
||||
const value = form.get(key);
|
||||
return value instanceof File && value.size > 0 ? value : null;
|
||||
}
|
||||
|
||||
interface ActionContext {
|
||||
api: ApiClient;
|
||||
form: FormData;
|
||||
params: Record<string, string>;
|
||||
locals: App.Locals;
|
||||
url: URL;
|
||||
}
|
||||
|
||||
export function authedAction<R>(
|
||||
handler: (context: ActionContext) => R | Promise<R>,
|
||||
unauthorizedMessage = 'Inicia sesión.'
|
||||
) {
|
||||
return async (event: RequestEvent) => {
|
||||
if (!event.locals.accessToken) return fail(401, { message: unauthorizedMessage });
|
||||
const form = await event.request.formData();
|
||||
return handler({
|
||||
api: apiFor(event),
|
||||
form,
|
||||
params: event.params as Record<string, string>,
|
||||
locals: event.locals,
|
||||
url: event.url
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function unwrapOrError<T>(
|
||||
result: { data?: T; error?: unknown; response?: Response },
|
||||
message: string,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formString } from '$lib/server/api';
|
||||
import { formString } from '$lib/server/forms/fields';
|
||||
import { ALBUM_EARLIEST_YEAR, LIMITS } from '$lib/validation';
|
||||
|
||||
interface AlbumFormBody {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export function formString(form: FormData, key: string): string {
|
||||
return String(form.get(key) ?? '');
|
||||
}
|
||||
|
||||
export function formFile(form: FormData, key: string): File | null {
|
||||
const value = form.get(key);
|
||||
return value instanceof File && value.size > 0 ? value : null;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formFile, formString } from '$lib/server/api';
|
||||
import { formFile, formString } from '$lib/server/forms/fields';
|
||||
import { LIMITS } from '$lib/validation';
|
||||
|
||||
interface PlaylistFormBody {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { formFile, formString } from '$lib/server/api';
|
||||
import { formFile, formString } from '$lib/server/forms/fields';
|
||||
import { LIMITS } from '$lib/validation';
|
||||
|
||||
interface TrackUploadBody {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
|
||||
export function loginRedirect(url: URL): never {
|
||||
redirect(302, `/auth?returnTo=${encodeURIComponent(url.pathname + url.search)}`);
|
||||
}
|
||||
|
||||
export function requireUser(locals: App.Locals, url: URL): SessionUser {
|
||||
if (!locals.user) loginRedirect(url);
|
||||
return locals.user;
|
||||
}
|
||||
|
||||
export function optionalUser(
|
||||
locals: App.Locals,
|
||||
url: URL,
|
||||
allowAnonymousListening: boolean
|
||||
): SessionUser | null {
|
||||
if (locals.user) return locals.user;
|
||||
if (!allowAnonymousListening) loginRedirect(url);
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user