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
7 changes: 4 additions & 3 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
- run: npm ci
- run: npx biome ci
client-build:
Expand All @@ -23,7 +23,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
- run: npm ci
- run: cd client && bash build.sh
server-build:
Expand All @@ -33,6 +33,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
- run: npm ci
- run: cd server && npm run build
- run: cd server && npm run typecheck
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20 AS builder
FROM node:24 AS builder
WORKDIR /app

COPY package*.json ./
Expand All @@ -10,7 +10,7 @@ COPY common ./common
COPY server ./server
RUN npm run build:server

FROM node:20-slim
FROM node:24-slim
WORKDIR /app

RUN apt-get update && apt-get install -y openssl && rm -rf /var/lib/apt/lists/*
Expand Down
13 changes: 2 additions & 11 deletions client/src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Footer from "../components/Footer";
import Header from "../components/Header";
import { briefProjectReviver } from "../revivers";
import type { BriefProject } from "../types";
import { API_ENDPOINT } from "../utils";
import { API_ENDPOINT, readErrorMessage } from "../utils";

const client = hc<AppType>(API_ENDPOINT);

Expand All @@ -29,16 +29,7 @@ export default function HomePage() {
const parsedData = data.map((p) => briefProjectReviver(p));
setInvolvedProjects(parsedData);
} else {
let errorMessage = "イベントの取得に失敗しました。";
try {
const data = await res.json();
const err = data as unknown as { message: string }; // Middleware のレスポンスは Hono RPC の型に乗らない
if (typeof err.message === "string" && err.message.trim()) {
errorMessage = err.message.trim();
}
} catch (_) {
// レスポンスがJSONでない場合は無視
}
const errorMessage = await readErrorMessage(res, "イベントの取得に失敗しました。");
setToast({
message: errorMessage,
variant: "error",
Expand Down
27 changes: 6 additions & 21 deletions client/src/pages/Project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { EXTERNAL_LINKS } from "../constants/links";
import dayjs from "../lib/dayjs";
import { projectReviver } from "../revivers";
import type { Project } from "../types";
import { API_ENDPOINT, FRONTEND_ORIGIN } from "../utils";
import { API_ENDPOINT, FRONTEND_ORIGIN, readErrorMessage } from "../utils";

const client = hc<AppType>(API_ENDPOINT);

Expand Down Expand Up @@ -59,15 +59,7 @@ export default function ProjectPage() {
const parsedData = projectReviver(data);
setProject(parsedData);
} else {
let errorMessage = "プロジェクトの取得に失敗しました。";
try {
const data = await res.json();
if (data && typeof data.message === "string" && data.message.trim()) {
errorMessage = data.message.trim();
}
} catch (_) {
// レスポンスがJSONでない場合は無視
}
const errorMessage = await readErrorMessage(res, "プロジェクトの取得に失敗しました。");
setToast({
message: errorMessage,
variant: "error",
Expand Down Expand Up @@ -254,17 +246,10 @@ export default function ProjectPage() {
});
setTimeout(() => setToast(null), 3000);
} else {
let errorMessage = "更新に失敗しました。";
try {
const data = await res.json();
if (data && typeof data.message === "string" && data.message.trim()) {
errorMessage = data.message.trim();
} else if (res.status === 403) {
errorMessage = "権限がありません。";
}
} catch (_) {
if (res.status === 403) errorMessage = "権限がありません。";
}
const errorMessage = await readErrorMessage(
res,
(res.status as number) === 403 ? "権限がありません。" : "更新に失敗しました。",
);
setToast({
message: errorMessage,
variant: "error",
Expand Down
12 changes: 2 additions & 10 deletions client/src/pages/eventId/Submission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Calendar, type Highlight } from "../../components/Calendar";
import Header from "../../components/Header";
import { projectReviver } from "../../revivers";
import type { Project, Slot } from "../../types";
import { API_ENDPOINT } from "../../utils";
import { API_ENDPOINT, readErrorMessage } from "../../utils";

const client = hc<AppType>(API_ENDPOINT);

Expand Down Expand Up @@ -103,15 +103,7 @@ export default function SubmissionPage() {
const parsedData = projectReviver(data);
setProject(parsedData);
} else {
let errorMessage = "プロジェクトの取得に失敗しました。";
try {
const data = await res.json();
if (data && typeof data.message === "string" && data.message.trim()) {
errorMessage = data.message.trim();
}
} catch (_) {
// レスポンスがJSONでない場合は無視
}
const errorMessage = await readErrorMessage(res, "プロジェクトの取得に失敗しました。");
setToast({
message: errorMessage,
variant: "error",
Expand Down
16 changes: 16 additions & 0 deletions client/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
export const API_ENDPOINT = import.meta.env.VITE_API_ENDPOINT || "http://localhost:3000";
export const FRONTEND_ORIGIN = import.meta.env.VITE_FRONTEND_ORIGIN || "http://localhost:5173";

/**
* エラーレスポンスの `{ message }` を読む。読めなければ `fallback` を返す。
* サーバーの onError やミドルウェアが返すエラーは Hono RPC の型に乗らないので、型を付けずに読む。
*/
export async function readErrorMessage(res: { json(): Promise<unknown> }, fallback: string): Promise<string> {
try {
const data = await res.json();
if (data && typeof data === "object" && "message" in data && typeof data.message === "string") {
return data.message.trim() || fallback;
}
} catch (_) {
// レスポンスがJSONでない場合は無視
}
return fallback;
}
Loading
Loading