Hook
server/hooks에 작성하는 HTTP Hook입니다.
요청 Hook
- *.hook.ts는 URL을 만들지 않고 모든 HTTP handler 앞에서 실행됩니다.
- hook 파일은 이름 오름차순으로 실행하며 next()가 다음 hook 또는 handler를 호출합니다.
- 인증, 요청 기록, header 처리와 공통 context 구성에 사용합니다.
// server/hooks/client-ip.hook.ts
export default async (
request: Request,
context: ApiContext,
next: HookNext
) => {
context.clientIp = request.headers.get("cf-connecting-ip")
|| request.headers.get("x-real-ip")
|| request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()
|| "local";
return next();
};파일 이름 규칙
- *.task.ts는 config.cron 시간에 실행합니다.
- *.job.ts는 job.<파일명>(data)로 등록합니다.
- *.hook.ts는 모든 HTTP handler 앞에서 실행합니다.
- server/routes/*.ws.ts는 양방향 WebSocket 연결을 처리합니다.
- server/routes/*.sse.ts는 서버에서 클라이언트로 이벤트를 전송합니다.
- 기존 server/events와 server/jobs 파일은 각 표준 폴더로 이전합니다.
- Task, WebSocket과 SSE 샘플은 active: false로 시작하지만 에디터의 테스트 실행은 active와 관계없이 사용할 수 있습니다.
server/hooks/
client-ip.hook.ts # HTTP 요청 hook
server/routes/
hello.ts # GET /hello
chat.ws.ts # WebSocket endpoint /chat
stream.sse.ts # SSE endpoint /stream
server/tasks/
check.task.ts # cron 예약 작업
report.job.ts # XLSX 생성 비동기 작업SSE 기본 구조
- timer.interval은 100~3,600,000ms 범위에서 설정합니다.
- heartbeat 10초, 동시 연결 100개와 브라우저 retry 3,000ms는 Runtime 내부 고정값입니다.
// server/routes/stream.sse.ts
export const config = {
active: false,
auth: false,
timer: {
active: true,
immediate: true,
interval: 1_000
}
};
export const onOpen = async (stream: SseStream) => {
await stream.push({ event: "open", data: { time: now() } });
};
export const onTimer = async (stream: SseStream, count: number) => {
await stream.push({ event: "tick", data: { count, time: now() } });
};
export const onClose = (stream: SseStream) => {
console.log("SSE Closed:", stream.id);
};