npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-dev-bot

v1.5.8

Published

Vite/Next.js 플러그인 — 브라우저에서 Claude Code와 대화 + 컴포넌트 인스펙터.

Downloads

7,274

Readme

react-dev-bot

Vite / Next.js 플러그인 — 브라우저에서 AI(Claude Code) 대화·스크린샷·클릭 히스토리 수집 + 에디터↔브라우저 컴포넌트 인스펙터.

설치

pnpm add -D react-dev-bot
# 또는 npm i -D react-dev-bot / yarn add -D react-dev-bot

사전 조건:

  • Claude Code CLI가 로컬에 설치되어 있어야 함 (claude 커맨드가 PATH에 있어야 함)
  • Vite 5+ 또는 Next.js 14+ (App Router)
  • 컴포넌트 인스펙터 원본 경로 해석은 현재 Next.js 16 전용 (Turbopack/Webpack 모두). Next 13–15에서는 번들 경로가 표시될 수 있음 — 추후 지원 예정.

Vite 설치

vite.config.ts:

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react-swc";
import { devBot, inspectorCursorServer } from "react-dev-bot/vite";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");
  const locatorEnabled = env.VITE_LOCATOR === "true";
  if (env.REACT_EDITOR) process.env.REACT_EDITOR = env.REACT_EDITOR;

  return {
    build: {
      sourcemap: locatorEnabled ? "hidden" : false,
      ...(locatorEnabled && {
        rollupOptions: { output: { sourcemapExcludeSources: true } },
      }),
    },
    plugins: [
      ...(locatorEnabled ? [inspectorCursorServer()] : []),
      ...(mode === "development" ? [devBot()] : []),
      react(),
    ],
  };
});

하위 호환: import { devBot } from "react-dev-bot"도 계속 동작합니다.


Next.js 설치 (App Router)

1) API 라우트 (catch-all):

// app/api/dev/[...path]/route.ts
export { GET, POST } from "react-dev-bot/next/route";

/api/dev/bot, /api/dev/sessions, /api/dev/reload, /api/dev/inspector/open 등을 한 번에 처리합니다.

2) 루트 레이아웃에 <DevBot/> 마운트:

// app/layout.tsx
import { DevBot } from "react-dev-bot/next";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <DevBot />
        {children}
      </body>
    </html>
  );
}

<DevBot/>process.env.NODE_ENV === "development"에서만 활성화됩니다. 프로덕션에선 null 리턴.

3) (선택) 커스텀 경로:

<DevBot basePath="/api/my-dev" />

라우트 파일 위치도 app/api/my-dev/[...path]/route.ts로 맞추면 됩니다.

4) (권장) global-error.tsx — SSR throw 시에도 DevBot 살리기:

// app/global-error.tsx
"use client";
export { default } from "react-dev-bot/next/global-error";

page/route handler 의 throw 로 루트 레이아웃이 날아가는 상황에서도 DevBot 마운트를 유지해 narrative 를 뽑을 수 있게 합니다. 커스텀 UI가 필요하면 직접 global-error.tsx 를 만들고 안에 <DevBot /> 만 넣으면 됩니다.

5) (강력 권장) <DevBotErrorBoundary> — React render 에러 자동 리포트:

React render 에러는 window.error로 올라오지 않습니다. 바운더리가 없으면 트리 전체가 언마운트되고(DevBot UI 포함), 유저 앱에 이미 바운더리가 있어도 dev-bot 은 console.error 훅으로 부분적으로만 수거합니다 — DevBotErrorBoundary를 앞단에 두면 React 컴포넌트 스택까지 포함해 narrative 에 정확히 들어갑니다.

// app/layout.tsx
import { DevBot, DevBotErrorBoundary } from "react-dev-bot/next";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <DevBotErrorBoundary>{children}</DevBotErrorBoundary>
        <DevBot />
      </body>
    </html>
  );
}

componentDidCatch 에서 reportReactError 를 자동 호출해 React render 단계 에러도 narrative 에 포함됩니다. 개발 환경에서만 동작 (force prop 으로 prod 활성 가능).


환경변수

.env.development 예시:

VITE_LOCATOR=true
REACT_EDITOR=cursor
VITE_INSPECTOR_SSH_HOST=myhost       # SSH remote 환경만
VITE_INSPECTOR_ROOT=/home/user/src   # 프로젝트 절대경로(SSH 환경)

| 변수 | 역할 | |---|---| | VITE_LOCATOR | (Vite) true면 인스펙터 + sourcemap 생성 | | REACT_EDITOR | Alt+클릭 시 열 에디터 CLI (cursor, code 등) | | VITE_INSPECTOR_SSH_HOST | SSH remote 환경에서 딥링크 호스트 | | VITE_INSPECTOR_ROOT | SSH remote 환경에서 프로젝트 절대경로 |

dev 서버 프로세스에서 인식하는 추가 환경변수:

| 변수 | 역할 | |---|---| | DEVBOT_TOKEN | HTTP/MCP 엔드포인트 Bearer 토큰. 미설정 시 부팅 시점에 랜덤 UUID 생성 후 stderr에 출력 | | DEVBOT_REQUIRE_TOKEN | 1이면 Origin 기반 same-origin fallback을 끄고 토큰을 강제 | | DEVBOT_BUFFER_SIZE | 이벤트 링버퍼 용량 (기본 500) | | DEVBOT_LOG_BUFFER_SIZE | raw stdout/stderr 로그 링버퍼 용량 (기본 2000줄) | | DEVBOT_BLOB_MAX_BYTES | 단일 blob 최대 크기 (기본 64MB) | | DEVBOT_BLOB_TTL_MS | blob 보존 시간 (기본 10분) |


기능

1. AI 채팅 패널

페이지 우하단의 🔧 버튼으로 Claude와 대화. 자동 수집되는 정보:

  • 현재 화면 스크린샷 (html2canvas)
  • 최근 클릭 히스토리 + 각 클릭의 컴포넌트 스택
  • JS 런타임 에러 / (Vite) 빌드 에러 자동 감지
  • 과거 세션 재개 — 로컬에 저장된 Claude Code 세션 파일 자동 검출
  • 서브에이전트 위임 (v1.1.5+) — Task/TodoWrite 툴이 허용돼 복잡한 작업을 fresh-context 서브에이전트로 나눠 처리 가능

2. 컴포넌트 인스펙터

  • Alt + 클릭: 클릭한 컴포넌트의 JSX 선언 위치를 에디터에서 열기
  • 🎯 버튼: 컴포넌트 피커 모드 — 요소를 선택해 컴포넌트 스택을 채팅창에 삽입
  • (Vite only) 에디터 커서 ↔ 브라우저 하이라이트: inspectorCursorServer 플러그인이 활성화된 경우에만 지원 (Next.js는 별도 HMR 채널 없음)

Next.js 버전 주의: 원본 경로 해석은 Next 16에서만 검증됨. Next 16의 /__nextjs_original-stack-frames API 포맷({frames, isServer, ...}, line1/column1, file://${distDir}/...)에 맞춰져 있어, 13–15에서는 바디 포맷 차이로 500이 반환되고 번들 경로로 표시됩니다. 구버전 지원은 추후 추가 예정.

3. dev_page_outline — 페이지 기능 구조 조회 (MCP)

Claude가 dev_page_outline을 호출하면 현재 열린 브라우저 탭의 accessibility tree + React 컴포넌트 이름 + 이벤트 핸들러 플래그 합본을 텍스트 outline으로 반환.

main
├─ form [onSubmit]                          @LoginForm (src/auth/LoginForm.tsx:12)
│  ├─ textbox "Email" required empty        @EmailInput
│  ├─ textbox "Password" required empty     @PasswordInput
│  └─ button "Sign in" disabled             @LoginSubmitButton
└─ generic "Settings" [onClick]             @SettingsButton

용도:

  • "이 화면에 뭐가 있나 / 어떤 요소가 클릭 가능한가" 질문을 스크린샷 없이 해결 — 토큰 효율.
  • <div onClick> 같이 DOM 노드엔 리스너가 없지만 React props엔 있는 핸들러를 fiber memoizedProps 경로로 복구 (Playwright MCP/CDP가 구조적으로 못 잡는 정보).
  • 각 노드의 소스 컴포넌트 이름 → Claude가 수정 대상 파일 추론.

파라미터: rootSelector / depth / includeHidden / maxNodes (기본 2000) / maxTextBytes (기본 64KB).

제약:

  • 연결된 브라우저 탭이 없으면 "no browser connected" 에러 — dev 서버 띄우고 탭 열어둔 상태여야 함.
  • Accessibility tree는 80% 휴리스틱 (정식 WAI-ARIA 스펙 완전 준수 아님).
  • 놓치는 핸들러 패턴: 직접 useEffect + ref.current.addEventListener 기반 커스텀 훅. Radix/React Aria/Floating UI/dnd-kit/Framer Motion은 모두 커버.
  • Shadow DOM / iframe / Server Component 트리 제외.

4. Edit-verify 루프 닫기 (MCP, v1.1+)

Claude가 코드 수정 → "내 수정이 뭘 만들었나" 확인하는 자율 사이클을 위한 3개 도구:

1) cp = dev_checkpoint()           // 수정 직전 시점 cursor
2) [코드 edit]
3) dev_wait_for_change()           // 다음 HMR/compile 이벤트까지 대기
4) dev_events_since(cp, severity)  // 내가 만든 변화만 isolate

핵심 의의: dev_events에 직접 sinceMono 넘기는 것을 id 기반 cursor로 추상화 — Claude가 timestamp 직접 관리하지 않고 "이 시점부터" 질문을 안전하게 만듦.

중요한 한계: dev_wait_for_changesyntactic verify만 가능 (컴파일·HMR 성공). "의도한 동작 동작" 같은 semantic 정합성은 별도 검증 필요. 응답에 warning 필드 자동 포함.

관련 도구:

  • dev_event(id) 응답에 curl·harEntry 자동 (network 이벤트일 때) — 실패 요청 즉시 재현
  • dev_events(format="har") — 여러 network 이벤트를 HAR 1.2 archive로 export (Playwright/proxy 도구 import 용)

5. 프로덕션/preview에서 인스펙터 사용 (Vite)

React _debugStack은 개발 모드에서만 생성되므로 일반 빌드에선 동작하지 않습니다. 권장 방식: devBot({ useDevReact: true }) 옵션 — Vite mode 는 production 유지(minify/treeshake 정상)하면서 React 만 dev 번들로 해석. 자세한 설정/비용은 #useDevReact 원리 / 비용 섹션 참고.


정보 카탈로그 — Push vs Pull

dev-bot이 수집하는 정보를 Claude에게 전달하는 두 경로:

  • Push (🔧 버튼): 유저가 버튼을 눌러 메시지를 보낼 때 자동 첨부되는 컨텍스트.
  • Pull (MCP): Claude 인스턴스가 필요할 때 스스로 호출하는 도구. runBotStreamclaude --mcp-config로 자동 주입 — Claude가 참조하는 mcp-config 키 이름은 dev-bot (MCP initialize 응답의 serverInfo.namereact-dev-bot).

| 정보 유형 | 수집 위치 | Push (🔧 자동첨부) | Pull (MCP 도구) | 관련 HTTP | |---|---|---|---|---| | 페이지 기능 outline (a11y tree + 컴포넌트 이름 + onClick 플래그) | 브라우저 | ❌ | dev_page_outline() | POST /dev/browser-rpc (SSE) | | 현재 화면 스크린샷 | 브라우저 (html2canvas) | ✅ | ❌ (Phase C 예정) | POST /dev/blob | | 클릭 히스토리 + 컴포넌트 스택 | 브라우저 | ✅ | ❌ (Phase C 예정) | — | | 브라우저 런타임 에러 (window.error, unhandledrejection, Error Boundary) | 브라우저 reporter | ✅ (narrative에 포함) | dev_events(source="browser-runtime") | GET /dev/events | | 브라우저 console 로그 | 브라우저 reporter | ⚠️ 최근 에러 윈도우 내만 | dev_events(source="console") | GET /dev/events | | 컴파일 에러 (Vite/Next) | dev 서버 훅 | ✅ | dev_events(source="compile") | GET /dev/events | | SSR throw / Route handler 에러 | console.error 훅 | ✅ | dev_events(source="ssr") | GET /dev/events | | Dev 서버 stderr (에러 패턴만) | process stderr 훅 | ✅ | dev_events(source="dev-server") | GET /dev/events | | Dev 서버 raw stdout/stderr 전체 | process stdout/stderr 훅 | ❌ (narrative 노이즈 방지) | dev_logs() | GET /dev/logs | | HMR 업데이트/전체리로드 | Vite HMR 훅 | ⚠️ 최근 윈도우 내만 | dev_events(source="hmr") | GET /dev/events | | 네트워크 요청/응답 | 브라우저 reporter | ⚠️ 최근 윈도우 내만 | dev_events(source="network") | GET /dev/events | | 에러 단건 전체 페이로드 (stack·meta·blobIds) | 링버퍼 byId 인덱스 | 🔧 버튼 대화 중 참조 가능 | dev_event({id}) | GET /dev/event/:id | | 에러 중심 타임라인 + markdown | 링버퍼 윈도우 | ✅ (🔧 버튼이 이걸로 구성) | dev_narrative({errorId?, windowMs?}) — errorId 생략 시 최근 error 자동 탐색. 응답에 uncertaintyWarning 포함 | GET /dev/narrative/:id, GET /dev/narrative/recent | | 시점 cursor (체크포인트) | 메모리 Map | ❌ | dev_checkpoint(label?){id, mono, wall} | — | | 체크포인트 이후 이벤트 | 링버퍼 since 쿼리 | ❌ | dev_events_since(checkpointId) | — | | HMR/컴파일 다음 이벤트 대기 | event-buffer subscriber | ❌ | dev_wait_for_change(timeoutMs?) | — | | 네트워크 → curl/HAR 변환 | network-export | 🔧 dev_event 응답 필드 | dev_event(id) 응답에 curl·harEntry 자동, dev_events(format="har") bulk | — | | 컴포넌트 트리 / props / state | — | ❌ (Phase C) | ❌ (Phase C) | — | | 라우트 인벤토리 | — | ❌ (Phase C) | ❌ (Phase C) | — | | Runtime env 스냅샷 | — | ❌ (Phase C) | ❌ (Phase C) | — |

요약

  • Push는 "유저가 보고 있는 순간의 맥락"(스크린샷·클릭·최근 에러 narrative)에 특화 — 정보 선별·토큰 효율 우선.
  • Pull은 "Claude가 필요할 때 조회" — dev_logs는 특히 raw 출력이라 push에 안 들어감. 모호한 질문("왜 이래", "화면이 안 떠")에 Claude가 자발적으로 dev_narrative 호출해 맥락 파악.

MCP 통합 — 동작 방식

runBotStreamclaude CLI를 spawn할 때 자동으로 수행:

  1. 현재 dev 서버 포트에서 MCP 엔드포인트 URL 계산 (예: http://127.0.0.1:3000/api/dev/__mcp).
  2. 임시 디렉터리에 mcp-config.json 작성 — Bearer 토큰(DEVBOT_TOKEN 또는 자동 생성)을 Authorization 헤더로 포함.
  3. --mcp-config <temp-path> 를 CLI 인자에 추가.
  4. 시스템 프롬프트에 dev_logs / dev_events / dev_event / dev_narrative / dev_checkpoint / dev_events_since / dev_wait_for_change / dev_page_outline 사용법 안내.

인증: MCP 엔드포인트는 일반 HTTP 엔드포인트와 같은 DEVBOT_TOKEN 인증을 공유. Origin 검증으로 DNS rebinding 기본 방어. 배포/원격 시나리오에선 DEVBOT_REQUIRE_TOKEN=1로 토큰 필수화.

지원 메서드: initialize, tools/list, tools/call, 그리고 standard notifications. 리소스/프롬프트/스트리밍·샘플링은 미지원 (Phase B 후속).


엔드포인트 레퍼런스

<DevBot/>devBot()이 등록하는 경로:

| 경로 (Vite 기본) | 경로 (Next.js 기본) | 메서드 | 역할 | |---|---|---|---| | /dev/bot | /api/dev/bot | POST | Claude 채팅 (SSE) | | /dev/__mcp | /api/dev/__mcp | POST | MCP JSON-RPC 엔드포인트 | | /dev/logs | /api/dev/logs | GET | raw stdout/stderr 덤프 | | /dev/events | /api/dev/events | GET/POST | 이벤트 링버퍼 조회/수집 | | /dev/event | /api/dev/event | POST | 단건 이벤트 수집 | | /dev/event/:id | /api/dev/event/:id | GET | 단건 이벤트 상세 | | /dev/narrative/:id | /api/dev/narrative/:id | GET | 에러 중심 narrative | | /dev/narrative/recent | /api/dev/narrative/recent | GET | 최근 윈도우 narrative | | /dev/browser-rpc | /api/dev/browser-rpc | GET (SSE) | 서버→브라우저 RPC (dev_page_outline 등) | | /dev/browser-rpc/result | /api/dev/browser-rpc/result | POST | 브라우저 RPC 결과 반환 | | /dev/blob | /api/dev/blob | POST | blob 업로드 | | /dev/blob/:id | /api/dev/blob/:id | GET | blob 조회 | | /dev/handshake | /api/dev/handshake | GET | 토큰 핸드셰이크 | | /dev/reload | /api/dev/reload | GET/POST | 브라우저 reload SSE | | /dev/sessions | /api/dev/sessions | GET | 세션 목록 | | /dev/session/:id | /api/dev/session/:id | GET | 세션 메시지 | | /dev/restart | /api/dev/restart | POST | Vite dev 재시작 (Next.js: no-op) | | /__inspector/open | /api/dev/inspector/open | POST | 에디터에서 파일 열기 | | — | /api/dev/dist-dir | GET | (Next.js only) 인스펙터용 dist 경로 조회 |

쿼리 파라미터:

  • /dev/logs?limit=500&stream=stdout|stderr&sinceMono=...
  • /dev/events?limit=100&source=...&minSeverity=error&sinceMono=...
  • /dev/narrative/recent?windowMs=10000

Claude가 브라우저를 새로고침하도록 요청할 때:

curl -s -X POST http://localhost:5173/dev/reload       # Vite
curl -s -X POST http://localhost:3000/api/dev/reload   # Next.js

보안 (preview/외부 배포)

  • sourcesContent: false (위 Vite config에 포함) — .map 파일에 원본 코드 미포함
  • hidden sourcemap — 브라우저 DevTools 자동 로드 안 됨, 인스펙터만 명시적 fetch
  • 어드민 패널이 인증 뒤에 있다면 .map 파일도 같은 인증으로 보호됨
  • 정적 파일을 공개 CDN으로 서빙한다면 .map 차단 필요 (인스펙터도 차단되므로 프록시 엔드포인트 구현)

원리

  1. React dev 모드에서 모든 JSX element에 _debugStack = new Error() 부여
  2. 브라우저에서 DOM 요소의 __reactFiber$로 fiber 접근
  3. fiber chain을 walk하며 _debugStack에서 JSX 호출 위치 추출
  4. sourcemap으로 번들 줄번호 → 원본 TS 줄번호 역추적

React 19의 formatOwnerStack()에 의해 _debugStack이 string으로 교체되는 경우도 처리합니다.


배포 환경 (prod 빌드) 모드 — Phase E

dev 모드와 별도로, build & deploy 된 환경에서도 동작하는 standalone 리포터가 있습니다. vite preview, next start, 사내 dogfooding 용 develop 배포 등.

설치

pnpm add -D react-dev-bot
# 또는: npm i -D react-dev-bot / yarn add -D react-dev-bot

빠른 시작 (Vite — 사내 develop 배포)

1) 빌드 환경변수 분리 — 진짜 production 에는 react-dev-bot 코드를 한 바이트도 넣지 않는 방식 (권장):

// app/entry.tsx
if (import.meta.env.VITE_DEVBOT_DEPLOY === "develop") {
  const { initDevBotProd } = await import("react-dev-bot/prod");
  initDevBotProd();   // ← v1.5.0 부터 명시적 호출 필요. 옵션 없으면 기본값.
}
VITE_DEVBOT_DEPLOY=develop pnpm build   # 사내 dogfooding 빌드 (react-dev-bot 동봉)
pnpm build                              # 진짜 production (react-dev-bot 0KB)

2) Vite 플러그인 설정 — env 게이팅을 함께 적용:

// vite.config.ts
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import { devBot } from "react-dev-bot/vite";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");
  const devbotDeploy = env.VITE_DEVBOT_DEPLOY === "develop";

  return {
    plugins: [
      react(),
      // dev 모드는 늘 활성, build 모드에선 develop 배포일 때만 useDevReact 켬.
      ...(mode === "development" || devbotDeploy
        ? [devBot({ useDevReact: devbotDeploy })]
        : []),
    ],
    build: {
      // 진짜 prod 에 .map 안 들어가게 게이팅. 'hidden' + sourcesContent: false 로
      // .map 만 동봉하고 원본 소스는 노출 안 함 (Stack 해석은 가능).
      sourcemap: devbotDeploy ? "hidden" : false,
      ...(devbotDeploy && {
        rollupOptions: { output: { sourcemapExcludeSources: true } },
      }),
    },
  };
});

왜 조건부인지: useDevReact: true 고정으로 두면 진짜 prod 빌드에도 React dev 번들이 들어가 ~80KB gzipped 낭비 (React 19 react-dom 의 dev↔prod 차이 측정값). sourcemap: true 고정도 .map 이 prod 산물에 동봉돼 노출. 둘 다 devbotDeploy 게이팅이 안전.

이렇게 빌드한 develop 배포에서는:

  • 모든 에러/console/network/click 이벤트가 IndexedDB 에 자동 영속 (기본 5000개 ring)
  • 우하단 📋 버튼 → 패널 (목록 / 상세 / 전체 timeline / 전체 dump / 제보하기)
  • 직원이 "제보하기" 클릭 → 문제 요소 짚기 → 코멘트 → 전송 (sendUrl 설정 시) 또는 IDB 만 저장

빠른 시작 (Next 16)

// app/devbot-loader.tsx
"use client";
import { useEffect } from "react";

export function DevBotLoader() {
  useEffect(() => {
    if (process.env.NEXT_PUBLIC_DEVBOT_DEPLOY !== "develop") return;
    void import("react-dev-bot/prod").then(({ initDevBotProd }) => {
      initDevBotProd();   // ← v1.5.0 부터 명시적 호출 필요
    });
  }, []);
  return null;
}

// app/layout.tsx
import { DevBotLoader } from "./devbot-loader";
// ...
<body><DevBotLoader />{children}</body>
// next.config.ts
export default { productionBrowserSourceMaps: true };
NEXT_PUBLIC_DEVBOT_DEPLOY=develop pnpm build   # 사내
pnpm build                                      # 진짜 production

initDevBotProd 옵션

v1.5.0 breaking change: side-effect import (import "react-dev-bot/prod") 만으로 자동 init 하던 동작 제거. ESM 평가 순서상 사용자의 옵션 설정이 무시되는 버그가 있었음. 이제 반드시 명시 호출:

import { initDevBotProd } from "react-dev-bot/prod";

initDevBotProd({
  enabled: import.meta.env.VITE_DEVBOT_DEPLOY === "develop",  // 런타임 kill switch
  capture: true,             // IDB 영속 (기본 true)
  viewer: true,              // 📋 floating 패널 (기본 true)
  clicks: true,              // 클릭 트래커 (기본 true)
  captureScreenshots: false, // 클릭마다 스크린샷 (기본 false, opt-in — webhook payload 에 인터리브)
  maxEvents: 5000,           // IDB ring 상한 (기본 5000)
  sendUrl: "https://example.com/devbot/ingest",  // 제보 전송 endpoint (선택, 단일 sender 단축형)
});

sendUrl 미설정 시 제보가 IDB 의 user-report event 로만 저장 — 직원이 뷰어에서 JSON 다운로드 해서 수동 공유.

여러 sender 등록 — prodSenders 네임스페이스

webhook 한 곳뿐 아니라 GitHub Issue prefill / mailto / 자체 sender 까지 동시에 노출하려면 senders 옵션:

import { initDevBotProd, prodSenders } from "react-dev-bot/prod";

initDevBotProd({
  captureScreenshots: true,
  senders: [
    prodSenders.webhook({
      url: "https://devbot-receiver.example.com/devbot",
      label: "🚀 Claude 분석",
      // (선택) HMAC 서명 — receiver 가 secret 으로 검증해 비악의적 요청 필터링.
      // ⚠️ secret 이 client bundle 에 포함됨 — anti-spam 용도, 진짜 인증 X.
      hmac: { secret: import.meta.env.VITE_DEVBOT_WEBHOOK_SECRET ?? "" },
    }),
    prodSenders.githubIssue({ repo: "myorg/myrepo", labels: ["bug", "from-devbot"] }),
    prodSenders.mailto({ to: "[email protected]" }),
  ],
});

모달 "전송" 버튼이 등록한 sender 별로 노출. 첫 번째가 primary 색상. 자체 Sender 구현 (Slack worker / 사내 ticketing API 등) 도 같은 인터페이스로 등록 가능 — 자세한 시그니처와 receiver 구현 예시는 docs/webhook-payload.md 참조.

이름의 prod prefix 가 곧 "prod 모드 전용" 임을 알려줌. dev 모드(🔧 Claude 직결)에는 webhook 개념 자체가 없습니다.

빌드 메타 (소비자 앱 git sha / branch)

배포된 산출물에서 "어떤 commit 으로 빌드됐는지" 알면 회귀 추적이 빨라집니다. webhook payload meta.appBuild + window.__devBotProd.appBuild 로 노출.

Vite — 자동 (무설정)

devBot() 플러그인이 빌드 시점에 자동 캡처해 define 주입. 사용자가 따로 설정할 게 없음.

탐지 우선순위:

  1. CI/PaaS 환경변수 — Vercel(VERCEL_GIT_COMMIT_SHA/REF), Netlify(COMMIT_REF/BRANCH), Cloudflare Pages(CF_PAGES_*), GitHub Actions(GITHUB_SHA/REF_NAME), Render(RENDER_GIT_*).
  2. 로컬 gitgit rev-parse HEAD + git status --porcelain (dirty flag).
  3. 둘 다 실패 시 builtAt 만 + source: "unknown".

확인:

window.__devBotProd.appBuild
// → { sha: "9ee0d52", branch: "main", dirty: false, builtAt: "...", source: "vercel" }

Next.js — 수동 주입 (env var → initDevBotProd 옵션)

Next 의 webpack/turbopack 은 우리 vite plugin 의 define 경로가 안 맞아서 직접 주입:

# 빌드 스크립트 (package.json scripts 또는 CI)
NEXT_PUBLIC_DEVBOT_APP_SHA=$(git rev-parse --short HEAD) \
NEXT_PUBLIC_DEVBOT_APP_BRANCH=$(git rev-parse --abbrev-ref HEAD) \
next build
// app/devbot-loader.tsx
"use client";
import { useEffect } from "react";

export function DevBotLoader() {
  useEffect(() => {
    if (process.env.NEXT_PUBLIC_DEVBOT_DEPLOY !== "develop") return;
    void import("react-dev-bot/prod").then(({ initDevBotProd }) => {
      initDevBotProd({
        appBuild: {
          sha: process.env.NEXT_PUBLIC_DEVBOT_APP_SHA,
          branch: process.env.NEXT_PUBLIC_DEVBOT_APP_BRANCH,
          source: "manual",
        },
      });
    });
  }, []);
  return null;
}

Vercel 에서 Next 배포 시 VERCEL_GIT_COMMIT_SHA 가 빌드 환경에 이미 있으니 process.env.VERCEL_GIT_COMMIT_SHA 를 그대로 써도 됨 (단 NEXT_PUBLIC_* 접두 없으면 client bundle 에 안 들어가니, next.configenv 로 노출 필요):

// next.config.ts
export default {
  env: {
    NEXT_PUBLIC_DEVBOT_APP_SHA: process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7),
    NEXT_PUBLIC_DEVBOT_APP_BRANCH: process.env.VERCEL_GIT_COMMIT_REF,
  },
};

옵션 override

자동 감지 결과를 덮고 싶거나 별도 메타를 추가하려면 initDevBotProd({ appBuild }) 옵션이 항상 우선:

initDevBotProd({
  appBuild: { sha: "abc1234", branch: "feature/x", source: "manual" },
});

Webhook payload (제보 전송 시)

prodSenders.webhook / sendUrl 로 보내지는 본문은 DevBotReport v1 schema. LLM-ready content blocks(text/image 인터리브) + 구조화 events + 라우팅 meta 형태로, receiver 가 받자마자 multimodal LLM(Claude/GPT-4V/Gemini)에 zero-translation 으로 forward 가능.

전체 TypeScript 타입, 샘플 payload, receiver 구현 예시(Hono/Express), HMAC 검증 패턴 등은 별도 문서 참고:

📄 docs/webhook-payload.md

요약:

interface DevBotReport {
  schemaVersion: "1";
  id: string;                     // browser-issued UUID
  createdAt: string;              // ISO 8601
  userMessage: string;            // 사용자 코멘트
  source: { url: string; title?: string; userAgent?: string; viewport?: {...} };
  content: ContentBlock[];        // Anthropic Messages API 포맷, chronological text/image 인터리브 (사용자 코멘트+첨부 → 컨텍스트 → 에러 → 타임라인)
  events: ReportEvent[];          // 구조화 NormalizedEvent[] + imageIndex
  meta?: { devBotVersion?, platform?, env?, clickCount?, consoleErrorCount?, appBuild?: { sha?, branch?, dirty?, builtAt?, source? }, ... };
  pickedElement?: PickedElement | null;
}

동작 매트릭스 (Vite vs Next prod)

| 기능 | Vite prod | Next 16 prod | 비고 | |---|---|---|---| | 에러 자동 캡처 (window.error / unhandledrejection) | ✅ | ✅ | reporter capture phase 등록 | | 에러 stack → 원본 .tsx:line 해석 | ✅ | ✅ | .map 동봉 필수. Next 는 chunk↔map basename 다름 → sourceMappingURL 주석 fetch 경로 사용 | | Console / fetch / XHR 캡처 | ✅ | ✅ | reporter 그대로 | | 클릭 트래커 (tag, text, 좌표, selector) | ✅ | ✅ | DOM 정보만 | | Intrinsic JSX 위치 (data-devbot-src) | ✅ | ❌ | Vite 플러그인 babel transform. Next 는 turbopack 이라 미적용 | | 컴포넌트 owner chain | useDevReact: true 시 ✅ | ❌ | React dev 번들 + fiber._debugSource | | IndexedDB 영속 + view-time 그룹/카운트 | ✅ | ✅ | DB react-dev-bot-prod, 기본 5000 events ring | | 📋 floating 뷰어 (목록/상세/dump) | ✅ | ✅ | vanilla DOM | | 제보하기 (인스펙터 + 코멘트 + 전송) | ✅ | ✅ | sendUrl 옵션으로 외부 endpoint POST | | window.__devBotProd API (events.*, startSendFlow, ...) | ✅ | ✅ | 콘솔 검증 / 외부 도구 통합 |

useDevReact 원리 / 비용

devBot({ useDevReact: true }) 가 빌드 모드일 때 자동으로:

  • process.env.NODE_ENV='development' 강제
  • Vite define 으로 bundle 안의 process.env.NODE_ENV"development" 치환
  • resolve.conditions: ['development', ...] 추가 → react/jsx-dev-runtime 이 실제 jsxDEV 함수 export

Vite mode 자체는 production 유지 (minify/treeshake 정상). React 만 dev 번들로 해석돼 fiber._debugSource 가 채워지고 기존 dev 모드 fiber walker 가 prod 에서 그대로 동작.

비용: 번들 +~80KB gzipped (React 19 react-dom dev↔prod 차이 실측), 런타임 2~3x. 사내 dogfooding 한정, 외부 사용자 prod 에선 끄기.

Next 동등 메커니즘은 turbopack JSX 옵션 조사 필요 (현재 미지원).

Phase E 한계 요약

  • 컴포넌트 owner chain 은 Vite + useDevReact 옵션 한정 (Next prod 미지원)
  • Intrinsic 위치 (data-devbot-src) 는 Vite 한정
  • 운영 안전장치 (PII redact / quota graceful degradation 등) 일부 미구현

production 배포 vs develop 배포 — 환경 분리

진짜 production (외부 사용자) 과 develop 배포 (사내 dogfooding) 를 구분하려면 두 축:

축 1 — 번들 자체 포함 여부 (build-time, 핵심)

react-dev-bot 코드가 진짜 prod 번들에 0바이트 들어가게 하려면 conditional dynamic import:

// app/entry.ts
if (import.meta.env.VITE_DEVBOT_DEPLOY === "develop") {
  const { initDevBotProd } = await import("react-dev-bot/prod"); // develop 배포만 번들 포함
  initDevBotProd();
}

빌드 명령:

VITE_DEVBOT_DEPLOY=develop pnpm build   # 사내 dogfooding 용
pnpm build                              # 진짜 production — react-dev-bot 0 KB

Next.js 도 동일 패턴 — process.env.NEXT_PUBLIC_DEVBOT_DEPLOY === "develop" 같이.

축 2 — 포함됐을 때 feature 토글 (runtime)

dynamic import 가 어려운 환경 (CSP / 구식 번들러) 또는 직원이 인스턴스별로 끄고 싶을 때:

import { initDevBotProd } from "react-dev-bot/prod";
initDevBotProd({
  enabled: import.meta.env.VITE_DEVBOT_DEPLOY === "develop",
  // false 면 모든 install 스킵, window.__devBotProd 도 노출 안 함.
});

주의: 이 경로는 코드는 번들에 들어감 — react-dev-bot/prod entry 자체 ~56KB gzipped (실측), useDevReact 추가 시 +80KB. 진짜 prod 에서 0KB 원하면 축 1 필수.

옵션 조합 가이드

| 시나리오 | 축 1 | 축 2 옵션 | |---|---|---| | 사내 develop 배포 (직원 dogfooding) | dynamic import 활성 | 기본값 그대로 (모든 feature on) | | 진짜 production | dynamic import 비활성 | n/a (번들 0) | | Sentry-like 가벼운 prod 캡처 | 활성 | { viewer: false, clicks: false } 로 에러 캡처만 | | 일시 비활성 (디버깅 / opt-out) | 활성 | { enabled: false } |


dev / prod 저장소 분리 — 의도적 split

| | dev | prod | |---|---|---| | In-memory ringbuffer | server-side core/event-buffer.ts (Node 메모리) | browser-side 같은 모듈 (브라우저 메모리) | | 영속 layer | 옵션 (devBot({ persistEvents: true }) 시 IDB 추가) | 기본 ON — IDB ring (기본 5000개) | | MCP/Claude 접근 | server memory 에 zero-latency 직접 query | n/a (외부 ingest 채널로) | | 외부 전송 | n/a (Claude 가 직접 spawn) | prodSenders.{webhook,githubIssue,mailto} (or sendUrl 단축형) / JSON dump 수동 공유 |

왜 통일 안 했나 — 한쪽으로 통일해 봤더니 잃는 게 더 컸음:

  • 양쪽 IDB only 로 가면: dev 의 MCP 도구가 browser IDB 에 접근하려 매번 browser-rpc 우회 (~수백 ms 지연), 또 server 에서 발생하는 이벤트 (dev-server stderr / SSR throw / process-capture) 를 IDB 로 자연스레 못 적재. browser tab 이 닫혀 있는 동안엔 데이터 접근 불가.
  • 양쪽 server memory only 는 prod 에 서버 부재라 불가능 — 사이드카/ingest 서버 추가 인프라 부담.
  • 양쪽 IDB + server mirror 는 정합성 관리 복잡, 중복 저장.

대신 API surface 는 양쪽 동일 — 핵심 함수가 core/narrative.tsbuildNarrative 하나로 묶여 있고, 데이터 스키마 (core/events.ts) 도 단일. 즉 narrative markdown / JSON export 형식은 어디서든 동일 shape. 어떤 환경에서 만든 dump 든 같은 ingest 채널로 흘려보낼 수 있음.

옵션 정리:

  • devBot({ persistEvents: true, maxPersistedEvents: 5000 }) — dev 도 IDB 영속 켜기 (서버 재시작/브라우저 종료 너머 보존)
  • initDevBotProd({ sendUrl: "https://..." }) — prod 의 "제보하기" 가 narrative+코멘트+element 를 POST (단일 sender 단축형)
  • initDevBotProd({ senders: [prodSenders.webhook(...), prodSenders.githubIssue(...), ...] }) — 멀티 sender 등록 (모달에 버튼 여러 개)
  • initDevBotProd({ maxEvents: 1000 }) — prod IDB ring 줄이기

알려진 한계

dev-bot 이 수집하지 못하는 에러 유형 (설계상 또는 React/Next 구조상):

  • Hydration mismatch — React 19는 mismatch 를 recoverable recovery 로 처리 (throw 가 아니라 내부 onRecoverableError 콜백). createRoot 제어권이 없으면 후킹 불가. dev 모드에서는 Next 오버레이가 서버/클라 값 diff 까지 매우 선명하게 보여주니 그걸로 확인.
  • 초기 hydration 완료 전 발생한 에러 — reporter 가 useEffect 기반이라 hydration 이후에 설치됨. 그 이전 구간의 window.error/unhandledrejection 은 누락 가능.
  • Web Worker / Service Worker / iframe 내부 에러 — 별도 실행 context 라 현재 reporter 가 도달 못함.
  • try/catch 로 삼킨 에러 — 근본적으로 불가.
  • 유저 Error Boundary 가 삼킨 뒤 console.error 까지 억제한 에러 — React 는 바운더리가 잡은 에러를 console.error 로 자동 로그하고 dev-bot 이 console 훅으로 수거하므로 대부분 잡힘. 하지만 유저 바운더리가 로그까지 억제하면(또는 React 의 내부 로깅을 패치로 제거하면) 못 봄. 일반적으로는 <DevBotErrorBoundary> 마운트 + React 기본 로그 유지로 커버됨.
  • SSR fetch 실패 (Next 서버 컴포넌트/route handler 의 외부 API 호출) — Node fetch 미패치. Phase D (사이드카) 로 검토했으나 현재 보류.
  • Next turbopack 빌드 실패 시 전체 /api/dev/* 작동 불능 — 유저 파일 구문 에러 하나로 앱 전체 컴파일 실패 → dev-bot 라우트도 500. 프로세스 분리(Phase D 사이드카) 로 검토했으나 현재 보류.

라이선스

MIT