Yak Docs
SDKs

JavaScript SDK

The @yak-io/javascript package provides the core client SDK and server handlers. It works with any JavaScript runtime that supports the Fetch API.

When to Use

  • Building with non-React frameworks (Vue, Svelte, Solid, etc.)
  • Need server handlers for custom runtimes (Cloudflare Workers, Deno, Bun)
  • Building a custom integration without React components

For React apps, use @yak-io/react. For Next.js, use @yak-io/nextjs.

Installation

npm install @yak-io/javascript
pnpm add @yak-io/javascript
yarn add @yak-io/javascript
bun add @yak-io/javascript

Server Handlers

Create API endpoints that serve route configuration and handle tool calls:

import { createYakHandler } from "@yak-io/javascript/server";

const { GET, POST } = createYakHandler({
  routes: [
    { path: "/", title: "Home" },
    { path: "/pricing", title: "Pricing" },
  ],
  tools: [
    {
      id: "custom",
      getTools: async () => [
        {
          name: "greet",
          description: "Greet a user by name",
          input_schema: {
            type: "object",
            properties: { name: { type: "string" } },
            required: ["name"],
          },
        },
      ],
      executeTool: async (name, args) => {
        if (name === "greet") {
          return { message: `Hello, ${args.name}!` };
        }
        throw new Error(`Unknown tool: ${name}`);
      },
    },
  ],
});

export { GET, POST };

Route Schema

PropertyTypeRequiredDescription
pathstringYesURL path
titlestringNoHuman-readable title
descriptionstringNoBrief description for AI context

Dynamic Route Sources

Fetch routes from external sources:

const cmsRoutes = {
  id: "cms",
  getRoutes: async () => {
    const res = await fetch("https://cms.example.com/api/pages");
    return res.json();
  },
};

const { GET, POST } = createYakHandler({
  routes: [staticRoutes, cmsRoutes],
});

Client SDK

The YakClient class manages widget communication. For most use cases, use @yak-io/react or @yak-io/nextjs instead — this is the low-level API.

import { YakClient } from "@yak-io/javascript";

const client = new YakClient({
  appId: "your-app-id",
  onToolCall: async (name, args) => {
    const res = await fetch("/api/yak", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name, args }),
    });
    const data = await res.json();
    if (!data.ok) throw new Error(data.error);
    return data.result;
  },
  onReady: () => console.log("Widget ready"),
  onClose: () => console.log("Widget closed"),
});

client.mount();
client.setWidgetOpen(true);
client.sendPrompt("Help me");
client.unmount();

Configuration Options

OptionTypeDescription
appIdstringYour Yak application ID
onToolCall(name, args) => Promise<unknown>Tool execution handler
onToolCallComplete(event: ToolCallEvent) => voidCalled after each tool call completes
onRedirect(path: string) => voidNavigation handler
onReady() => voidCalled when the widget is ready
onClose() => voidCalled when the widget is closed
themeThemeWidget styling options

Runtime Examples

Cloudflare Workers

import { createYakHandler } from "@yak-io/javascript/server";

const { GET, POST } = createYakHandler({
  routes: [{ path: "/", title: "Home" }],
});

export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === "/api/yak") {
      if (request.method === "GET") return GET(request);
      if (request.method === "POST") return POST(request);
    }

    return new Response("Not Found", { status: 404 });
  },
};

Hono

import { Hono } from "hono";
import { createYakHandler } from "@yak-io/javascript/server";

const app = new Hono();

const { GET, POST } = createYakHandler({
  routes: [{ path: "/", title: "Home" }],
});

app.get("/api/yak", (c) => GET(c.req.raw));
app.post("/api/yak", (c) => POST(c.req.raw));

export default app;

Deno

import { createYakHandler } from "@yak-io/javascript/server";

const { GET, POST } = createYakHandler({
  routes: [{ path: "/", title: "Home" }],
});

Deno.serve(async (request) => {
  const url = new URL(request.url);

  if (url.pathname === "/api/yak") {
    if (request.method === "GET") return GET(request);
    if (request.method === "POST") return POST(request);
  }

  return new Response("Not Found", { status: 404 });
});

Bun

import { createYakHandler } from "@yak-io/javascript/server";

const { GET, POST } = createYakHandler({
  routes: [{ path: "/", title: "Home" }],
});

Bun.serve({
  port: 3000,
  async fetch(request) {
    const url = new URL(request.url);

    if (url.pathname === "/api/yak") {
      if (request.method === "GET") return GET(request);
      if (request.method === "POST") return POST(request);
    }

    return new Response("Not Found", { status: 404 });
  },
});

Express / Node.js

import express from "express";
import { createYakHandler } from "@yak-io/javascript/server";

const app = express();
app.use(express.json());

const { GET, POST } = createYakHandler({
  routes: [{ path: "/", title: "Home" }],
});

app.all("/api/yak", async (req, res) => {
  const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;

  const request = new Request(url, {
    method: req.method,
    headers: req.headers as HeadersInit,
    body: req.method !== "GET" ? JSON.stringify(req.body) : undefined,
  });

  const response = await (req.method === "POST" ? POST(request) : GET(request));

  res.status(response.status);
  response.headers.forEach((value, key) => res.setHeader(key, value));
  res.send(Buffer.from(await response.arrayBuffer()));
});

app.listen(3000);

TypeScript

Import types for your integrations:

// Client-side types
import type {
  YakClientConfig,
  Theme,
  ThemeColors,
  ToolCallHandler,
  ToolCallEvent,
} from "@yak-io/javascript";

// Server-side types
import type {
  RouteInfo,
  RouteSource,
  ToolDefinition,
  ToolSource,
  ToolExecutor,
  ToolCallPayload,
  ToolCallResult,
} from "@yak-io/javascript/server";

On this page