CAKE20

AI Web PaaS

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);
};