Next.js App Router への組み込み(cside-sdk)

導入はフェーズ 1:AI 設定(CSide コンソールと資格情報)と、フェーズ 2:サイトへの組み込みNext.js App Router への cside-sdk の追加)に分けます。サーバー側は cside-sdk/next、UI は cside-sdk/react を利用します。

フェーズ 1:AI 設定

CSide の管理画面で、埋め込むチャットがどのように応答するかを固めます。ここまで終えると、フェーズ 2 でアプリ側から参照する値が揃います。

  • アカウント作成とワークスペース/プロジェクトの準備
  • エージェントの作成と案内内容の設定(テンプレートやウィザードでたたき台を作り、文言や許可範囲を調整)
  • ナレッジやルール、公開スコープを確認して公開・反映する
  • API キーエージェント IDをコンソールから取得する(フェーズ 2 の環境変数に転記)

アプリ側の環境変数(フェーズ 1 の値を転記)

Next.js プロジェクトルートの .env.local に、コンソールで発行した値を設定する(キー名は固定)。API キーなど秘密情報はリポジトリにコミットしない。

CSIDE_API_KEY=
CSIDE_AGENT_ID=

ルートレイアウトはサーバーで評価できるため、 CSIDE_AGENT_ID NEXT_PUBLIC_ は通常不要。

フェーズ 2:サイトへの組み込み

フェーズ 1 が済んだうえで、対象の Next.js アプリに SDK とエンドポイントを追加します。CLI が .env.local を自動編集することはありません。

対象のアプリケーション(Next.js、App Router)

以降の手順は App Router 向けです。作業前に次を満たすこと。

  • package.json next 依存があること
  • app/ または src/app/ にルートレイアウト(例: layout.tsx)やルートがあり、App Router として成立していること

次の場合は cside-sdk の導入・変更は行わない

  • Pages Router のみ(app がなく pages のみ)と判断できる場合

構成が不明瞭で判定できない場合は推測で進めず、ルートレイアウトのパスや不足情報を確認する。

npm install と npx cside コマンド

プロジェクトルートで実行する。

npm install cside-sdk && npx cside init

サーバー再起動

開発サーバーを再起動して反映を確認する。組み込みが成功していればチャットウィジェットが画面右下に表示される想定。

npm run dev

npx cside init を使わない場合

npx cside init の代わりに、依存関係とファイルを手作業で追加する。

1. 依存関係

npm install cside-sdk

2. API ルート

app/api/cside/[[...slug]]/route.ts を追加する。ルートが src/app の場合は src/app/api/cside/[[...slug]]/route.ts

import {
  handleCsideChatPost,
  handleCsideEmbedContextGet,
  handleCsideHostApiPreparePost,
} from "cside-sdk/next";

export const runtime = "nodejs";
export const maxDuration = 60;

type CsideSlug = string[] | undefined;

function routeKey(slug: CsideSlug): "chat" | "embed-context" | "prepare" | null {
  if (!slug?.length) return null;
  if (slug.length === 1 && slug[0] === "chat") return "chat";
  if (slug.length === 1 && slug[0] === "embed-context") return "embed-context";
  if (slug.length === 2 && slug[0] === "host-api" && slug[1] === "prepare") return "prepare";
  return null;
}

export async function GET(
  req: Request,
  ctx: { params: Promise<{ slug?: string[] }> },
): Promise<Response> {
  const { slug } = await ctx.params;
  if (routeKey(slug) === "embed-context") return handleCsideEmbedContextGet(req);
  return Response.json({ error: "Not found" }, { status: 404 });
}

export async function POST(
  req: Request,
  ctx: { params: Promise<{ slug?: string[] }> },
): Promise<Response> {
  const { slug } = await ctx.params;
  const key = routeKey(slug);
  if (key === "chat") return handleCsideChatPost(req);
  if (key === "prepare") return handleCsideHostApiPreparePost(req);
  return Response.json({ error: "Not found" }, { status: 404 });
}

3. Tailwind v4

app/globals.css の末尾に追記する例。

/* cside-sdk */
@source "../node_modules/cside-sdk/dist/**/*.mjs";

src/app/globals.css なら、ファイル位置から node_modules/cside-sdk/dist への相対パスに読み替える(例: @source "../../node_modules/cside-sdk/dist/**/*.mjs";)。

4. ルートレイアウト

既存の html / body / children を壊さず CsideProvider で包む。 agentId には process.env.CSIDE_AGENT_ID ?? "" を渡す。

import type { ReactNode } from "react";
import { CsideProvider } from "cside-sdk/react";

export default function Layout({ children }: { children: ReactNode }) {
  const agentId = process.env.CSIDE_AGENT_ID ?? "";

  return (
    <html lang="ja">
      <body>
        <CsideProvider agentId={agentId}>
          {children}
        </CsideProvider>
      </body>
    </html>
  );
}

注意

  • API キーなど秘密情報をリポジトリにコミットしない
  • Tailwind の @source はプロジェクト構成に合わせて調整する