@yak-io/nuxt 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,29 +1,39 @@
1
1
  # @yak-io/nuxt
2
2
 
3
- Nuxt 3 integration for the Yak embeddable chat widget. Provides a plugin-compatible factory that auto-mounts on `app:mounted` and provides the widget API via Nuxt's plugin system.
3
+ > 📚 **Full documentation:** https://docs.yak.io/docs/sdks/nuxt
4
+ >
5
+ > 🤖 **For LLMs / AI agents:** https://docs.yak.io/llms.txt
4
6
 
5
- ## Installation
7
+ Nuxt 3 SDK for [Yak](https://docs.yak.io) — an embeddable AI assistant (text chat **and** push-to-talk voice) for web apps. Register `createYakProvider` in a client plugin and expose the `YakApi` (Vue refs) through `useNuxtApp()`.
6
8
 
7
9
  ```bash
8
10
  pnpm add @yak-io/nuxt
9
11
  ```
10
12
 
13
+ ## Exports
14
+
15
+ | Export | Kind | Purpose |
16
+ | --- | --- | --- |
17
+ | `createYakProvider(options)` | fn | Create a widget instance. Returns a `YakApi` with refs + `mount`/`destroy`. |
18
+ | `enableYakLogging` / `disableYakLogging` / `isYakLoggingEnabled` | fn | Toggle verbose SDK logging. |
19
+ | Types | — | `YakProviderOptions`, `YakApi`, `ToolCallEventHandler`, plus core types from `@yak-io/javascript`. |
20
+
11
21
  ## Quickstart
12
22
 
13
- ### 1. Create a Nuxt plugin
23
+ ### 1. Create a client plugin
14
24
 
15
25
  ```ts
16
26
  // plugins/yak.client.ts
17
- import { defineNuxtPlugin } from "#app";
18
- import { createYakProvider, enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/nuxt";
27
+ import { createYakProvider } from "@yak-io/nuxt";
19
28
 
20
29
  export default defineNuxtPlugin((nuxtApp) => {
21
30
  const runtimeConfig = useRuntimeConfig();
22
31
 
23
32
  const yak = createYakProvider({
24
- appId: runtimeConfig.public.yakAppId,
33
+ appId: runtimeConfig.public.yakAppId as string,
34
+ mode: "both", // "chat" | "voice" | "both" — default "chat"
35
+ trigger: true, // show the floating launcher pill
25
36
  theme: { position: "bottom-right", colorMode: "system" },
26
- trigger: { label: "Ask with AI" },
27
37
  getConfig: async () => {
28
38
  const res = await fetch("/api/yak");
29
39
  return res.json();
@@ -38,89 +48,103 @@ export default defineNuxtPlugin((nuxtApp) => {
38
48
  if (!data.ok) throw new Error(data.error);
39
49
  return data.result;
40
50
  },
41
- onRedirect: (path) => {
42
- navigateTo(path);
43
- },
51
+ onRedirect: (path) => navigateTo(path),
44
52
  });
45
53
 
46
- // Mount on client, clean up on HMR
47
54
  nuxtApp.hook("app:mounted", () => yak.mount());
48
- if (import.meta.hot) {
49
- import.meta.hot.dispose(() => yak.destroy());
50
- }
51
-
52
- return {
53
- provide: {
54
- yak,
55
- yakLogging: { enableYakLogging, disableYakLogging, isYakLoggingEnabled },
56
- },
57
- };
55
+ if (import.meta.hot) import.meta.hot.dispose(() => yak.destroy());
56
+
57
+ return { provide: { yak } };
58
58
  });
59
59
  ```
60
60
 
61
- ### 2. Access in components
61
+ The `.client.ts` suffix keeps the widget out of SSR. Use `runtimeConfig.public.yakAppId` (set via `NUXT_PUBLIC_YAK_APP_ID`).
62
62
 
63
- ```ts
64
- // Any component <script setup>
63
+ ### 2. Access it in components
64
+
65
+ ```vue
66
+ <script setup lang="ts">
65
67
  const { $yak } = useNuxtApp();
66
- const { open, openWithPrompt, isOpen, isReady } = $yak;
68
+ const { open, openWithPrompt, isOpen } = $yak;
69
+ </script>
70
+
71
+ <template>
72
+ <button @click="open">Open chat</button>
73
+ <button @click="openWithPrompt('How do I get started?')">Get help</button>
74
+ <span v-if="isOpen">Chat is open</span>
75
+ </template>
67
76
  ```
68
77
 
69
- `isOpen` and `isReady` are Vue `readonly` refs:
78
+ `isOpen`/`isReady` are `readonly` Vue refs.
79
+
80
+ ## Voice
81
+
82
+ Set `mode: "voice"` or `mode: "both"`, then drive the session. `voiceStart()` must run from a user gesture (browser mic requirement).
83
+
84
+ ```vue
85
+ <script setup lang="ts">
86
+ const { $yak } = useNuxtApp();
87
+ const { voiceToggle, voiceLoading, voiceMachine } = $yak;
88
+ </script>
70
89
 
71
- ```html
72
90
  <template>
73
- <button @click="open">Open Chat</button>
74
- <span v-if="isOpen">Chat is open</span>
91
+ <button @click="voiceToggle" :disabled="voiceLoading">
92
+ {{ voiceMachine.state === "idle" ? "Start voice" : `Stop (${voiceMachine.state})` }}
93
+ </button>
75
94
  </template>
76
95
  ```
77
96
 
78
- ### 3. Subscribe to tool events
97
+ ## Tool events
79
98
 
80
99
  ```ts
81
100
  const { $yak } = useNuxtApp();
82
101
 
83
102
  $yak.subscribeToToolEvents((event) => {
84
- if (event.ok && event.name.startsWith("tasks.")) {
85
- refreshTasks();
86
- }
103
+ // { name, args, ok, result?, error? }
104
+ if (event.ok && event.name.startsWith("tasks.")) refreshTasks();
87
105
  });
88
106
  ```
89
107
 
90
- ## API Reference
108
+ ## API reference
91
109
 
92
110
  ### `createYakProvider(options)`
93
111
 
94
- Creates a Yak widget instance. Returns a `YakApi` with Vue-reactive refs for reactive state.
95
-
96
- You must call `yak.mount()` on the client side (e.g., in the `app:mounted` hook) and `yak.destroy()` when cleaning up.
97
-
98
- **Options:**
99
-
100
- | Option | Type | Description |
101
- |--------|------|-------------|
102
- | `appId` | `string` | Your Yak app ID |
103
- | `getConfig` | `ChatConfigProvider` | Async function returning routes + tools. Called on first open. |
104
- | `onToolCall` | `ToolCallHandler` | Handle tool invocations from the assistant |
105
- | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | Handle GraphQL schema tool calls |
106
- | `onRESTSchemaCall` | `RESTSchemaHandler` | Handle REST/OpenAPI schema tool calls |
107
- | `theme` | `Theme` | Position, color mode, and custom colors |
108
- | `onRedirect` | `(path: string) => void` | Navigation handler (defaults to `window.location.assign`) |
109
- | `disableRestartButton` | `boolean` | Hide the restart session button |
110
- | `trigger` | `boolean \| TriggerButtonConfig` | Built-in trigger button |
112
+ Returns a `YakApi`. Call `yak.mount()` on the client (e.g. the `app:mounted` hook) and `yak.destroy()` on cleanup.
113
+
114
+ | Option | Type | Default | Description |
115
+ | --- | --- | --- | --- |
116
+ | `appId` | `string` | — | Your Yak app ID (required). |
117
+ | `mode` | `"chat" \| "voice" \| "both"` | `"chat"` | Which surfaces the widget exposes. |
118
+ | `trigger` | `boolean \| TriggerButtonConfig` | `false` | Show the floating pill. **Set `true`** to display it; `TriggerButtonConfig` recolors it. |
119
+ | `getConfig` | `ChatConfigProvider` | — | Async provider of routes + tools. Called on open / voice start. |
120
+ | `onToolCall` | `ToolCallHandler` | | Executes a tool the assistant calls. |
121
+ | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | | Handles GraphQL schema tool calls. |
122
+ | `onRESTSchemaCall` | `RESTSchemaHandler` | | Handles REST/OpenAPI schema tool calls. |
123
+ | `theme` | `Theme` | | Position, color mode, and colors. |
124
+ | `onRedirect` | `(path: string) => void` | `window.location.assign` | Navigation handler. |
125
+ | `disableRestartButton` | `boolean` | `false` | Hide the restart-session button. |
111
126
 
112
127
  ### `YakApi`
113
128
 
114
129
  ```ts
115
130
  type YakApi = {
116
- isOpen: DeepReadonly<Ref<boolean>>; // Vue readonly ref
117
- isReady: DeepReadonly<Ref<boolean>>; // Vue readonly ref
131
+ // chat
132
+ isOpen: DeepReadonly<Ref<boolean>>;
133
+ isReady: DeepReadonly<Ref<boolean>>;
134
+ chatLoading: DeepReadonly<Ref<boolean>>; // isOpen && !isReady
118
135
  open: () => void;
119
136
  close: () => void;
120
137
  openWithPrompt: (prompt: string) => void;
121
138
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
122
- mount: () => void; // Call in app:mounted hook
123
- destroy: () => void; // Call on HMR dispose / cleanup
139
+ // voice
140
+ voiceMachine: DeepReadonly<Ref<VoiceMachine>>; // { state, errorMessage? }
141
+ voiceLoading: DeepReadonly<Ref<boolean>>; // state === "connecting"
142
+ voiceStart: () => Promise<void>;
143
+ voiceStop: () => Promise<void>;
144
+ voiceToggle: () => Promise<void>;
145
+ // lifecycle
146
+ mount: () => void; // call in app:mounted
147
+ destroy: () => void; // call on HMR dispose / cleanup
124
148
  };
125
149
  ```
126
150
 
@@ -129,9 +153,7 @@ type YakApi = {
129
153
  ```ts
130
154
  import { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/nuxt";
131
155
 
132
- enableYakLogging(); // Enable verbose SDK logs
133
- disableYakLogging(); // Disable SDK logs
134
- isYakLoggingEnabled(); // → boolean
156
+ enableYakLogging(); // verbose SDK logs
135
157
  ```
136
158
 
137
159
  ## Types
@@ -145,11 +167,13 @@ import type {
145
167
  ToolCallHandler,
146
168
  ToolCallEvent,
147
169
  Theme,
148
- TriggerButtonConfig,
170
+ WidgetMode,
149
171
  WidgetPosition,
172
+ VoiceState,
173
+ VoiceMachine,
150
174
  } from "@yak-io/nuxt";
151
175
  ```
152
176
 
153
177
  ## License
154
178
 
155
- Proprietary — see LICENSE file.
179
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/plugin.d.ts CHANGED
@@ -13,18 +13,35 @@ export type YakProviderOptions = {
13
13
  disableRestartButton?: boolean;
14
14
  trigger?: boolean | TriggerButtonConfig;
15
15
  };
16
+ /** Reactive handle for controlling the Yak widget — chat + voice — from Nuxt. */
16
17
  export type YakApi = {
18
+ /** Whether the chat panel is currently open. */
17
19
  isOpen: DeepReadonly<Ref<boolean>>;
20
+ /** Whether the chat iframe is ready to receive messages. */
18
21
  isReady: DeepReadonly<Ref<boolean>>;
22
+ /** Whether the chat is opening but not yet interactive (`isOpen && !isReady`). */
23
+ chatLoading: DeepReadonly<Ref<boolean>>;
24
+ /** Open the chat panel. */
19
25
  open: () => void;
26
+ /** Close the chat panel. */
20
27
  close: () => void;
28
+ /** Open the chat panel and send a specific prompt. */
21
29
  openWithPrompt: (prompt: string) => void;
30
+ /** Subscribe to tool-call completion events; returns an unsubscribe function. */
22
31
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
32
+ /** Current voice state-machine snapshot. `idle` when mode is `chat`. */
23
33
  voiceMachine: DeepReadonly<Ref<VoiceMachine>>;
34
+ /** Whether the voice session is establishing its connection (`state === "connecting"`). */
35
+ voiceLoading: DeepReadonly<Ref<boolean>>;
36
+ /** Start a voice session. Must be invoked from a user gesture. */
24
37
  voiceStart: () => Promise<void>;
38
+ /** Stop the current voice session. */
25
39
  voiceStop: () => Promise<void>;
40
+ /** Toggle voice: start if idle/error, stop if active. */
26
41
  voiceToggle: () => Promise<void>;
42
+ /** Mount the widget into the DOM. */
27
43
  mount: () => void;
44
+ /** Tear down the widget and remove its listeners. */
28
45
  destroy: () => void;
29
46
  };
30
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAGzB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,GAAG,EAAiB,MAAM,KAAK,CAAC;AAIjE,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IACrE,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9C,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAmGrE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAGzB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,YAAY,EAAE,KAAK,GAAG,EAAiB,MAAM,KAAK,CAAC;AAI3E,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CACzC,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,MAAM,GAAG;IAEnB,gDAAgD;IAChD,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,4DAA4D;IAC5D,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,kFAAkF;IAClF,WAAW,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACxC,2BAA2B;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,sDAAsD;IACtD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,iFAAiF;IACjF,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAErE,wEAAwE;IACxE,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9C,2FAA2F;IAC3F,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,kEAAkE;IAClE,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,sCAAsC;IACtC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,yDAAyD;IACzD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,qCAAqC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,qDAAqD;IACrD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAwGrE"}
package/dist/plugin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { INITIAL_VOICE_MACHINE, logger, YakEmbed, } from "@yak-io/javascript";
2
- import { readonly, ref } from "vue";
2
+ import { computed, readonly, ref } from "vue";
3
3
  // ── Provider factory ────────────────────────────────────────────────────────
4
4
  /**
5
5
  * Creates a yak widget (chat + voice) for Nuxt.
@@ -75,9 +75,12 @@ export function createYakProvider(options) {
75
75
  logger.warn("Voice start failed", err);
76
76
  }
77
77
  };
78
+ const chatLoading = computed(() => isOpen.value && !isReady.value);
79
+ const voiceLoading = computed(() => voiceMachine.value.state === "connecting");
78
80
  return {
79
81
  isOpen: readonly(isOpen),
80
82
  isReady: readonly(isReady),
83
+ chatLoading,
81
84
  open: () => embed.open(),
82
85
  close: () => embed.close(),
83
86
  openWithPrompt: (prompt) => embed.openWithPrompt(prompt),
@@ -88,6 +91,7 @@ export function createYakProvider(options) {
88
91
  };
89
92
  },
90
93
  voiceMachine: readonly(voiceMachine),
94
+ voiceLoading,
91
95
  voiceStart,
92
96
  voiceStop: () => embed.voiceStop(),
93
97
  voiceToggle: () => embed.voiceToggle(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yak-io/nuxt",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Nuxt 3 module for embedding yak chatbot",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -25,6 +25,7 @@
25
25
  "node": ">=18"
26
26
  },
27
27
  "files": [
28
+ "README.md",
28
29
  "dist",
29
30
  "LICENSE"
30
31
  ],
@@ -41,7 +42,7 @@
41
42
  "./package.json": "./package.json"
42
43
  },
43
44
  "dependencies": {
44
- "@yak-io/javascript": "0.8.0"
45
+ "@yak-io/javascript": "0.9.0"
45
46
  },
46
47
  "peerDependencies": {
47
48
  "nuxt": "^3.0.0",
@@ -53,6 +54,7 @@
53
54
  "vue": "^3.5.34",
54
55
  "@repo/typescript-config": "0.0.0"
55
56
  },
57
+ "homepage": "https://docs.yak.io/docs/sdks/nuxt",
56
58
  "scripts": {
57
59
  "build": "tsc",
58
60
  "check-types": "tsc --noEmit",