Skip to main content
This page tracks API changes that require code updates, organized by the version that introduced them. Deprecations are safe to ignore short-term — the old shape keeps working until the removal version listed in the deprecation notice.

Deprecations at a glance

TypeScript will strike through deprecated signatures in your IDE. Hover for the replacement.

Breaking changes at a glance

When you bump @waniwani/sdk across a minor version (0.x minors can break), scan this page for every breaking change between your old and new version and apply the documented migration. Each one below is a mechanical rewrite an agent or codemod can apply in a single pass, followed by bun run typecheck && bun test.

0.15.0: lead becomes lead_qualified

The lead event is named lead_qualified, its helper is track.leadQualified(), and its properties are LeadQualifiedProperties: externalId, email, and name alongside source. The typed input is RevenueLeadQualifiedInput (RevenueLeadInput and LeadProperties no longer exist). lead_qualified means the person met your qualification bar (finished the qualifying questions, requested a demo, matched your target profile). It belongs at the node where qualification completes, not at flow entry; see Instrumentation for placement rules.

Why

lead under-specified what the event represented, so integrations fired it anywhere from flow entry to CRM push and funnels were not comparable across projects. The name now states the semantic, and the new properties (externalId as your CRM record id, plus email and name) give the dashboard real dedup and join keys instead of an anonymous count.

Before

After

All new properties are optional; a bare track.leadQualified({ source }) is valid.

Migration (codemod)

  1. Replace every .track.lead( call with .track.leadQualified(.
  2. Replace event: "lead" with event: "lead_qualified" in generic track() calls (and eventType: "lead" in the legacy shape).
  3. Replace type imports: RevenueLeadInputRevenueLeadQualifiedInput, LeadPropertiesLeadQualifiedProperties.
  4. Where the call site has them available, enrich the event: pass your lead record id as externalId, plus email and name.
  5. Run bun run typecheck && bun test.

Compatibility

  • track.lead() exists as a @deprecated alias since 0.15.1: it emits a lead_qualified event and will be removed in 0.16.0. On 0.15.0 exactly, the alias is absent and step 1 is required to compile.
  • The transport normalizes the event name "lead" to "lead_qualified" at runtime (since 0.15.1), so already-compiled pre-0.15 callers keep producing valid events. The EventType union does not accept "lead", so TypeScript call sites must migrate.

Verifying


0.14.0: addConditionalEdge declares its branch targets

addConditionalEdge now takes the reachable nodes explicitly as the second argument: addConditionalEdge(from, to, condition). The condition’s return type is constrained to to, so a branch can never route to an undeclared node, and the flow graph used for funnel analytics and Mermaid diagrams is correct by construction.

Why

Before 0.14.0, graph introspection discovered a conditional edge’s targets by stringifying the condition function and scanning its source for node names. That heuristic was fragile: it broke under minification, missed dynamically-computed targets, and produced false positives when a node id appeared as a comparison value or in a comment — so funnel analytics could show the wrong branches. Declaring to removes the guesswork entirely.

Before

After

Migration (codemod)

For each .addConditionalEdge(from, condition) call, insert a second argument: an array of every node the condition can return (including END if it returns END). The simplest reliable source for that array is the set of literal node names returned by the condition body.
  1. Find every two-argument .addConditionalEdge( call.
  2. Read the condition body and collect every node name (string literal or END) it can return.
  3. Insert that list, deduplicated, as the new second argument — leaving the condition as the third.
  4. Run bun run typecheck. The compiler now flags any return value missing from to, so any over- or under-declared list surfaces immediately. Fix by aligning to with what the condition actually returns.

Verifying

If typecheck reports Type '"x"' is not assignable to type '"a" | "b"', the condition returns a node missing from to — add it. If it reports an unused-looking target, the condition never returns it — safe to leave (over-declaration is allowed) or trim.

0.12.0: Legacy reorganization

The MCP-widget-in-host stack (createTool / createResource / WidgetProvider and host bridge hooks) and the chat-server BFF adapters (toNextJsHandler, toExpressJsHandler, createApiHandler) were moved to dedicated @waniwani/sdk/legacy* entry points. New code should use createFlow from @waniwani/sdk/mcp and the direct-to-backend ChatEmbed from @waniwani/sdk/chat. The old entry points still re-export every symbol unchanged — your imports keep working without edits. The legacy entry points exist so you can adopt the final import paths now and avoid the next major bump.

Why

  • OSS-first framing. @waniwani/sdk/mcp is now the OSS surface: createFlow, StateGraph, KvStore, MemoryKvStore. No API key required, no hosted dependency on the core path.
  • Smaller default bundle. Splitting the legacy surface off lets host-only React hooks and the chat-server router stay out of the OSS bundle once the re-exports are dropped.
  • Sunset signal. The chat widget will talk directly to app.waniwani.ai in a future release, removing the need for a self-hosted BFF. The Next.js / Express adapters become unnecessary.

Migration matrix

Every row is a mechanical rewrite — no behavior changes, only the import path. An LLM or codemod can apply all of these in one pass. useWaniwani, UseWaniwaniOptions, and WaniwaniWidget stay on @waniwani/sdk/mcp/react — that hook is non-legacy.

What stays the same

These remain on @waniwani/sdk/mcp and are the recommended surface for new code:
  • createFlow, StateGraph, START, END, redacted, createFlowTestHarness, AddNodeConfig, all flow-related types
  • KvStore, MemoryKvStore, WaniwaniKvStore
  • withWaniwani, WithWaniwaniOptions
  • createTrackingRoute, TrackingRouteOptions
  • ScopedWaniWaniClient
  • McpServer, ZodRawShapeCompat (shared MCP types)
And on @waniwani/sdk:
  • waniwani(), defineConfig, WaniWaniError, all tracking helpers

Codemod recipe (one-shot)

An agent updating a downstream repo can apply these substitutions in order. Each is a string-level rewrite of an import … from "<path>" statement — semantics are preserved end-to-end.
If you split imports across files, the only ambiguous case is step 1 vs step 3 (Express) when both come from the same root. Mechanical rule: the source path determines the destination, not the symbol name. The same symbol does not appear in two unrelated source paths within this matrix.

Verifying a one-shot migration

After substituting, the codebase should still typecheck and run unchanged. Run:
If you see errors of the form Module '"@waniwani/sdk/mcp"' has no exported member 'X', it means that symbol is being moved entirely out of the old path in a later major (0.14.0). Until then the old import keeps working — the matrix above tells you the final destination.

Verifying a customer codebase has zero legacy imports

To audit a downstream repo for any remaining legacy imports:
The first command should produce hits (those are the new paths). The remaining commands should produce either zero hits, or the same lines as before the migration (meaning the back-compat shim is doing its job and you can defer the rewrite).

ChatCardChatEmbed

ChatCard is still exported but marked @deprecated. It wraps ChatEmbed with always-visible card chrome (header, border, fixed dimensions) and assumes the Waniwani-hosted backend.
ChatEmbed does not fetch /config or /tool against the Waniwani host — you point api at your own endpoint and (optionally) supply mcp.resourceEndpoint if your backend serves widget resources.

evals/* removed

The src/evals/* subtree (chat eval runner, scorers, reporter) was removed entirely. No re-export shim. If you imported runChatEval, createScorer, or any sibling from @waniwani/sdk/evals, the build will fail on upgrade — there is no equivalent in this release. Eval tooling has moved to the Waniwani platform and is no longer shipped in-SDK.

0.12.0: addNode object form

The positional .addNode(id, run, options?) signature is deprecated in favor of an options-bag form. Metadata sits at the top of the call where the eye lands, the handler is a named field, and future options can be added without widening a positional signature.

Before

After

What changed

  • id replaces the first positional argument.
  • run replaces the second positional argument (the handler).
  • label and hideFromFunnel move from the third options argument onto the same config object.
  • label is now optional. When omitted, it defaults to id. The positional form required label whenever you passed an options object.

Compatibility

Both signatures are supported. The positional form is marked @deprecated and will be removed in 0.13.0. You can mix the two within the same flow during the transition. There is no functional difference between the two shapes.

Type export

A new AddNodeConfig<TState, TName> type is exported from @waniwani/sdk/mcp if you need to type a config object outside the call site.