mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 23:19:39 -05:00
Fix HTTP OPTIONS request to /api/ (#2697)
This commit is contained in:
parent
650bd0028e
commit
fcefe17430
45
app/features/api-public/api-cors-middleware.server.ts
Normal file
45
app/features/api-public/api-cors-middleware.server.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
type MiddlewareArgs = {
|
||||
request: Request;
|
||||
context: unknown;
|
||||
};
|
||||
|
||||
type MiddlewareFn = (
|
||||
args: MiddlewareArgs,
|
||||
next: () => Promise<Response>,
|
||||
) => Promise<Response>;
|
||||
|
||||
const CORS_HEADERS = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, HEAD, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
||||
"Access-Control-Max-Age": "86400",
|
||||
};
|
||||
|
||||
export const apiCorsMiddleware: MiddlewareFn = async ({ request }, next) => {
|
||||
const url = new URL(request.url);
|
||||
const isApiRoute = url.pathname.startsWith("/api/");
|
||||
|
||||
if (!isApiRoute) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (request.method === "OPTIONS") {
|
||||
return new Response(null, {
|
||||
status: 204,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
|
||||
const response = await next();
|
||||
const newHeaders = new Headers(response.headers);
|
||||
|
||||
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
||||
newHeaders.set(key, value);
|
||||
}
|
||||
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: newHeaders,
|
||||
});
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { cors } from "remix-utils/cors";
|
||||
import * as ApiRepository from "~/features/api/ApiRepository.server";
|
||||
|
||||
async function loadApiTokensCache() {
|
||||
|
|
@ -23,12 +22,3 @@ export function requireBearerAuth(req: Request) {
|
|||
throw new Response("Invalid token", { status: 401 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleOptionsRequest(req: Request) {
|
||||
if (req.method === "OPTIONS") {
|
||||
throw await cors(req, new Response("OK", { status: 204 }), {
|
||||
origin: "*",
|
||||
credentials: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import {
|
||||
|
|
@ -8,10 +7,7 @@ import {
|
|||
weekNumberToDate,
|
||||
} from "~/utils/dates";
|
||||
import { parseParams } from "~/utils/remix.server";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetCalendarWeekResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -20,7 +16,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { week, year } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -39,7 +34,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
: null,
|
||||
}));
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
||||
function fetchEventsOfWeek(args: { week: number; year: number }) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { concatUserSubmittedImagePrefix } from "~/utils/kysely.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentOrganizationResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -17,7 +13,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -75,5 +70,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
})),
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { SendouQ } from "~/features/sendouq/core/SendouQ.server";
|
||||
import { parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetUsersActiveSendouqMatchResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -15,7 +11,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { userId } = parseParams({
|
||||
|
|
@ -29,5 +24,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
matchId: current?.matchId ?? null,
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import * as SQMatchRepository from "~/features/sendouq-match/SQMatchRepository.server";
|
||||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetSendouqMatchResponse, MapListMap } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -16,7 +12,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { matchId } = parseParams({
|
||||
|
|
@ -84,5 +79,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
},
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { concatUserSubmittedImagePrefix } from "~/utils/kysely.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTeamResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -16,7 +12,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id: teamId } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -48,5 +43,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
teamPageUrl: `https://sendou.ink/t/${team.customUrl}`,
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import * as TournamentRepository from "~/features/tournament/TournamentRepository.server";
|
||||
|
|
@ -11,10 +10,7 @@ import { i18next } from "~/modules/i18n/i18next.server";
|
|||
import { logger } from "~/utils/logger";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentMatchResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -22,7 +18,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const t = await i18next.getFixedT("en", ["game-misc"]);
|
||||
|
|
@ -181,5 +176,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
roundName: roundNameWithoutMatchIdentifier ?? null,
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentBracketStandingsResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -16,7 +12,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id, bidx } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -37,5 +32,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
})),
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import type { Bracket } from "~/features/tournament-bracket/core/Bracket";
|
||||
import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentBracketResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -17,7 +13,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id, bidx } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -51,7 +46,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
},
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
||||
function teams(bracket: Bracket) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetCastedTournamentMatchesResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -15,7 +11,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id } = parseParams({
|
||||
|
|
@ -47,5 +42,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
})) ?? [],
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import * as TournamentMatchRepository from "~/features/tournament-bracket/TournamentMatchRepository.server";
|
||||
import { parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentPlayersResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -15,7 +11,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id } = parseParams({
|
||||
|
|
@ -26,5 +21,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
const participants: GetTournamentPlayersResponse =
|
||||
await TournamentMatchRepository.userParticipationByTournamentId(id);
|
||||
|
||||
return cors(request, Response.json(participants));
|
||||
return Response.json(participants);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { ordinalToSp } from "~/features/mmr/mmr-utils";
|
||||
|
|
@ -11,10 +10,7 @@ import { databaseTimestampToDate } from "~/utils/dates";
|
|||
import { concatUserSubmittedImagePrefix } from "~/utils/kysely.server";
|
||||
import { parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentTeamsResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -22,7 +18,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const t = await i18next.getFixedT("en", ["game-misc"]);
|
||||
|
|
@ -170,7 +165,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
};
|
||||
});
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
||||
function toSeedingPowerSP(ordinals: (number | null)[]) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import { databaseTimestampToDate } from "~/utils/dates";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { id } from "~/utils/zod";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetTournamentResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -17,7 +13,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const { id } = parseParams({ params, schema: paramsSchema });
|
||||
|
|
@ -84,5 +79,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
isFinalized: Boolean(tournament.isFinalized),
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod/v4";
|
||||
import { identifierToUserIdQuery } from "~/features/user-page/UserRepository.server";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import { handleOptionsRequest } from "../api-public-utils.server";
|
||||
import type { GetUserIdsResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
identifier: z.string(),
|
||||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
|
||||
export const loader = async ({ params }: LoaderFunctionArgs) => {
|
||||
const { identifier } = parseParams({ params, schema: paramsSchema });
|
||||
|
||||
const user = notFoundIfFalsy(
|
||||
|
|
@ -27,5 +23,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
customUrl: user.customUrl,
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { jsonArrayFrom } from "kysely/helpers/sqlite";
|
||||
import type { LoaderFunctionArgs } from "react-router";
|
||||
import { cors } from "remix-utils/cors";
|
||||
import { z } from "zod";
|
||||
import { db } from "~/db/sql";
|
||||
import * as Seasons from "~/features/mmr/core/Seasons";
|
||||
|
|
@ -8,10 +7,7 @@ import { userSkills as _userSkills } from "~/features/mmr/tiered.server";
|
|||
import { i18next } from "~/modules/i18n/i18next.server";
|
||||
import { safeNumberParse } from "~/utils/number";
|
||||
import { notFoundIfFalsy, parseParams } from "~/utils/remix.server";
|
||||
import {
|
||||
handleOptionsRequest,
|
||||
requireBearerAuth,
|
||||
} from "../api-public-utils.server";
|
||||
import { requireBearerAuth } from "../api-public-utils.server";
|
||||
import type { GetUserResponse } from "../schema";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
|
|
@ -19,7 +15,6 @@ const paramsSchema = z.object({
|
|||
});
|
||||
|
||||
export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
||||
await handleOptionsRequest(request);
|
||||
requireBearerAuth(request);
|
||||
|
||||
const t = await i18next.getFixedT("en", ["weapons"]);
|
||||
|
|
@ -146,5 +141,5 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
|
|||
})),
|
||||
};
|
||||
|
||||
return await cors(request, Response.json(result));
|
||||
return Response.json(result);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import { Catcher } from "./components/Catcher";
|
|||
import { SendouToastRegion, toastQueue } from "./components/elements/Toast";
|
||||
import { Layout } from "./components/layout";
|
||||
import { Ramp } from "./components/ramp/Ramp";
|
||||
import { apiCorsMiddleware } from "./features/api-public/api-cors-middleware.server";
|
||||
import { getUser } from "./features/auth/core/user.server";
|
||||
import { userMiddleware } from "./features/auth/core/user-middleware.server";
|
||||
import {
|
||||
|
|
@ -51,7 +52,10 @@ import { IS_E2E_TEST_RUN } from "./utils/e2e";
|
|||
import { allI18nNamespaces } from "./utils/i18n";
|
||||
import { isRevalidation, metaTags, type SerializeFrom } from "./utils/remix";
|
||||
|
||||
export const middleware: Route.MiddlewareFunction[] = [userMiddleware];
|
||||
export const middleware: Route.MiddlewareFunction[] = [
|
||||
apiCorsMiddleware,
|
||||
userMiddleware,
|
||||
];
|
||||
|
||||
import "nprogress/nprogress.css";
|
||||
import "~/styles/common.css";
|
||||
|
|
|
|||
28
e2e/api-public.spec.ts
Normal file
28
e2e/api-public.spec.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { expect, seed, test } from "~/utils/playwright";
|
||||
|
||||
test.describe("Public API", () => {
|
||||
test("OPTIONS preflight request returns 204 with CORS headers", async ({
|
||||
page,
|
||||
}) => {
|
||||
await seed(page);
|
||||
|
||||
const response = await page.request.fetch("/api/tournament/1", {
|
||||
method: "OPTIONS",
|
||||
});
|
||||
|
||||
expect(response.status()).toBe(204);
|
||||
expect(response.headers()["access-control-allow-origin"]).toBe("*");
|
||||
expect(response.headers()["access-control-allow-methods"]).toContain("GET");
|
||||
expect(response.headers()["access-control-allow-headers"]).toContain(
|
||||
"Authorization",
|
||||
);
|
||||
});
|
||||
|
||||
test("GET request includes CORS headers in response", async ({ page }) => {
|
||||
await seed(page);
|
||||
|
||||
const response = await page.request.fetch("/api/tournament/1");
|
||||
|
||||
expect(response.headers()["access-control-allow-origin"]).toBe("*");
|
||||
});
|
||||
});
|
||||
74
package-lock.json
generated
74
package-lock.json
generated
|
|
@ -62,7 +62,6 @@
|
|||
"remix-auth": "^4.2.0",
|
||||
"remix-auth-oauth2": "^3.4.1",
|
||||
"remix-i18next": "^7.4.2",
|
||||
"remix-utils": "^9.0.0",
|
||||
"slugify": "^1.6.6",
|
||||
"swr": "^2.3.8",
|
||||
"web-push": "^3.6.7",
|
||||
|
|
@ -7399,7 +7398,7 @@
|
|||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@standard-schema/utils": {
|
||||
|
|
@ -12844,65 +12843,6 @@
|
|||
"react-router": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remix-utils": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remix-utils/-/remix-utils-9.0.0.tgz",
|
||||
"integrity": "sha512-xpDnw6hIjYbHR9/noE4lKNPRzfxvGai3XBQcjOjcwIwZVW9O1bdsnYAl+aqJ2fMXSQTNMjNuR8Cetn76HqwXCg==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/sergiodxa"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"type-fest": "^4.41.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edgefirst-dev/batcher": "^1.0.0",
|
||||
"@edgefirst-dev/jwt": "^1.2.0",
|
||||
"@edgefirst-dev/server-timing": "^0.0.1",
|
||||
"@oslojs/crypto": "^1.0.1",
|
||||
"@oslojs/encoding": "^1.1.0",
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"intl-parse-accept-language": "^1.0.0",
|
||||
"is-ip": "^5.0.1",
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-router": "^7.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@edgefirst-dev/batcher": {
|
||||
"optional": true
|
||||
},
|
||||
"@edgefirst-dev/jwt": {
|
||||
"optional": true
|
||||
},
|
||||
"@edgefirst-dev/server-timing": {
|
||||
"optional": true
|
||||
},
|
||||
"@oslojs/crypto": {
|
||||
"optional": true
|
||||
},
|
||||
"@oslojs/encoding": {
|
||||
"optional": true
|
||||
},
|
||||
"@standard-schema/spec": {
|
||||
"optional": true
|
||||
},
|
||||
"intl-parse-accept-language": {
|
||||
"optional": true
|
||||
},
|
||||
"is-ip": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-router": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
|
@ -13930,18 +13870,6 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.41.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
|
||||
"integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@
|
|||
"remix-auth": "^4.2.0",
|
||||
"remix-auth-oauth2": "^3.4.1",
|
||||
"remix-i18next": "^7.4.2",
|
||||
"remix-utils": "^9.0.0",
|
||||
"slugify": "^1.6.6",
|
||||
"swr": "^2.3.8",
|
||||
"web-push": "^3.6.7",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user