Get this on every PR automatically. Webhook fires, AI reviews, you approve.
Install on langchain-ai/deployment-cookbook →
// reviewed by pulllight
PullLight found 4 issues
1 high
2 medium
1 low
// convert to your repo
PullLight caught 4 1 high, 2 medium, 1 low on this PR.
Install on langchain-ai/deployment-cookbook to get this on every PR automatically — 60 seconds.
Findings
4 issues
high
auth
The `LANGSMITH_API_KEY` is exposed to the browser bundle via Vite's `envPrefix` config. This is acknowledged in comments, but the `getApiKey()` function returns it unconditionally and it is passed directly to `ManagedClient` and used in `createStreamClient()`. Any user who opens DevTools or inspects the bundle can extract the key and make arbitrary API calls against the LangSmith workspace. The README warning is present but the code has no guard or proxy path — for a demo repo that others will copy, this pattern will be replicated in production deployments. At minimum, the function should throw (or the client should refuse to initialize) when running in a non-localhost origin, rather than silently leaking the key.
// js-langsmith-managed/src/lib/chat/threads-client.ts:40
medium
race-condition
The `initStarted` ref guards against double-invocation, but `setMounted(true)` is only called inside the happy path after both `fetchThreads()` and `createThread()` succeed. If either async call throws, `mounted` stays `false` and `initStarted.current` stays `true`, so the effect never retries and the UI is permanently stuck on "Preparing chat…" with no error surfaced to the user.
// js-langsmith-managed/src/components/ChatApp.tsx:46
medium
error-handling
In `handleDelete`, after deleting the active thread and the list is empty, `createThread()` is called but any error it throws is unhandled and will propagate as an unhandled promise rejection. The surrounding `handleDelete` is an `async` callback passed to `onDelete` which is called with `onClick`; React does not catch async errors from event handlers, so the UI will silently break.
// js-langsmith-managed/src/components/ChatApp.tsx:68
low
logic
`threadId` is declared as a prop in the destructured parameter list (`{ onRunSettled }`) but the type annotation includes `threadId: string`. The prop is never used inside `Chat` — the component relies entirely on `useStreamContext` for thread state. This is harmless but the unused prop in the type creates a misleading contract and could cause confusion if callers assume the component uses it to scope the stream.
// js-langsmith-managed/src/components/Chat.tsx:17