@k8ordo/server

ガードと応答

ページは描画であって、応答を書きません。リクエストを通すかどうかと、応答にページ以外の何を付けるかは、ページより前に走る guard.ts が決めます。このページは、guard.ts の書き方、打ち切り方と通し方、responseHeaders() での添え方、guard が受け持つ範囲を説明します。

guard.ts

guard.ts はどの階層のディレクトリにも置け、そのディレクトリより下で答えるものの前に走ります。URL に沿って複数あれば、外側から 1 つずつ順に走ります。

bash
src/routes/
  layout.tsx
  guard.ts
  page.tsx
  admin/
    guard.ts
    page.tsx
    [id]/
      page.tsx
ts
// src/routes/admin/guard.ts
import type { Guard } from '@k8ordo/server/runtime';

const guard: Guard<'/admin'> = ({ request }) => {
  if (request.headers.get('cookie')?.includes('session=') === true) return;
  return new Response(null, { status: 303, headers: { location: '/login' } });
};

export default guard;

受け取るのは { request, params } です。request は届いたままの Request、params はそのディレクトリのパターンの params で、URL が運んだ文字列のままです。guard はどのレイアウトよりも上で走るので、スキーマが型を付ける前にいます。型は @k8ordo/server/runtime の Guard<P> で、生成された表も各 guard.ts をそのディレクトリのパターンで検査します。

打ち切るか、通すか

Response を返すと、それが答えになります。リダイレクトでも 401 でも 403 でもかまいません。その内側の guard も、下のページも走りません。何も返さなければ次の guard へ、最後の guard のあとは URL に答えるものへ渡ります。

応答に添える

通すときでも、最終的な応答に付けるものは添えられます。responseHeaders() は、何が答えるかにかかわらず最終的な応答が持つ Headers です。ページでも、そのペイロードでも、not-found でも、さらに内側の guard が打ち切った応答でも同じです。

ts
// src/routes/guard.ts
import { responseHeaders } from '@k8ordo/server/runtime';

export default function guard() {
  responseHeaders().set('x-content-type-options', 'nosniff');
}

答えがすでに持っているヘッダーは置き換えます。responseHeaders() は guard が走っている間だけ使え、それ以外の場所では throw します。ページは描画で、応答を書く描画は 2 つ目のハンドラになってしまうからです。

next() は無い

ページを走らせてその答えを受け取り、書き換えてから返す next() はありません。ページはストリーミングで返り、本文を書き終える前にヘッダーが送られます。だから guard が決められるのは、ページが始まる前だけです。

guard が受け持つもの

guard は、そのディレクトリより下のすべての URL の前に走ります。

  • ページと、クライアント遷移で取りに来るそのペイロード
  • そのページへの HEAD
  • そのページへ送られた Server Action
  • 下にある not-found.tsx。ルートの guard は、どれも答えない URL にも走ります

redirect.ts はどの guard よりも前に答えます。移転したディレクトリには、守るものが下にありません。

guard は Server Action そのものを守りません。アクションはどのページからでも呼べる関数で、呼んだページの URL へ送られます。アクションが要るものは、アクションの中で確かめます。 アクションとリクエスト

走る順番

guard は params のスキーマが URL を照合したあと、POST が運ぶ Server Action と描画より前に走ります。[locale] の下の guard は、URL が名指すロケールの中で走ります。

@k8ordo/static では

ファイルには守るリクエストがありません。@k8ordo/static は guard.ts を名指しで拒みます。ビルドでも vite dev でもです。

@k8ordo/static