@yak-io/angular 0.2.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,13 +1,23 @@
1
1
  # @yak-io/angular
2
2
 
3
- Angular integration for the Yak embeddable chat widget. Uses a factory function compatible with Angular's component and service patterns.
3
+ > 📚 **Full documentation:** https://docs.yak.io/docs/sdks/angular
4
+ >
5
+ > 🤖 **For LLMs / AI agents:** https://docs.yak.io/llms.txt
4
6
 
5
- ## Installation
7
+ Angular SDK for [Yak](https://docs.yak.io) — an embeddable AI assistant (text chat **and** push-to-talk voice) for web apps. `createYakProvider` returns a `YakApi`; bridge its state into Angular signals (or RxJS) with `subscribeToState`.
6
8
 
7
9
  ```bash
8
10
  pnpm add @yak-io/angular
9
11
  ```
10
12
 
13
+ ## Exports
14
+
15
+ | Export | Kind | Purpose |
16
+ | --- | --- | --- |
17
+ | `createYakProvider(options)` | fn | Create a widget instance. Returns a `YakApi` with `mount`/`destroy` + `subscribeToState`. |
18
+ | `enableYakLogging` / `disableYakLogging` / `isYakLoggingEnabled` | fn | Toggle verbose SDK logging. |
19
+ | Types | — | `YakProviderOptions`, `YakApi`, `YakState`, `ToolCallEventHandler`, plus core types from `@yak-io/javascript`. |
20
+
11
21
  ## Quickstart
12
22
 
13
23
  ### 1. Initialize in your root component
@@ -26,32 +36,27 @@ import { environment } from "../environments/environment";
26
36
  })
27
37
  export class AppComponent implements OnInit, OnDestroy {
28
38
  private router = inject(Router);
29
- private yak: YakApi;
30
-
31
- constructor() {
32
- this.yak = createYakProvider({
33
- appId: environment.yakAppId,
34
- theme: { position: "bottom-right", colorMode: "system" },
35
- trigger: { label: "Ask with AI" },
36
- getConfig: async () => {
37
- const res = await fetch("/api/yak");
38
- return res.json();
39
- },
40
- onToolCall: async (name, args) => {
41
- const res = await fetch("/api/yak", {
42
- method: "POST",
43
- headers: { "Content-Type": "application/json" },
44
- body: JSON.stringify({ name, args }),
45
- });
46
- const data = await res.json();
47
- if (!data.ok) throw new Error(data.error);
48
- return data.result;
49
- },
50
- onRedirect: (path) => {
51
- this.router.navigateByUrl(path);
52
- },
53
- });
54
- }
39
+ private yak: YakApi = createYakProvider({
40
+ appId: environment.yakAppId,
41
+ mode: "both", // "chat" | "voice" | "both" — default "chat"
42
+ trigger: true, // show the floating launcher pill
43
+ theme: { position: "bottom-right", colorMode: "system" },
44
+ getConfig: async () => {
45
+ const res = await fetch("/api/yak");
46
+ return res.json();
47
+ },
48
+ onToolCall: async (name, args) => {
49
+ const res = await fetch("/api/yak", {
50
+ method: "POST",
51
+ headers: { "Content-Type": "application/json" },
52
+ body: JSON.stringify({ name, args }),
53
+ });
54
+ const data = await res.json();
55
+ if (!data.ok) throw new Error(data.error);
56
+ return data.result;
57
+ },
58
+ onRedirect: (path) => this.router.navigateByUrl(path),
59
+ });
55
60
 
56
61
  ngOnInit() {
57
62
  this.yak.mount();
@@ -63,9 +68,7 @@ export class AppComponent implements OnInit, OnDestroy {
63
68
  }
64
69
  ```
65
70
 
66
- ### 2. Share via an Angular service
67
-
68
- Create a service to share the widget API across components:
71
+ ### 2. Share via a service
69
72
 
70
73
  ```ts
71
74
  // yak.service.ts
@@ -76,95 +79,108 @@ import type { YakApi } from "@yak-io/angular";
76
79
  export class YakService {
77
80
  private yak: YakApi | null = null;
78
81
  readonly isOpen = signal(false);
79
- readonly isReady = signal(false);
80
82
 
81
- setYak(yak: YakApi) {
83
+ register(yak: YakApi) {
82
84
  this.yak = yak;
83
- yak.subscribeToState(({ isOpen, isReady }) => {
84
- this.isOpen.set(isOpen);
85
- this.isReady.set(isReady);
86
- });
85
+ yak.subscribeToState((state) => this.isOpen.set(state.isOpen));
87
86
  }
88
87
 
89
88
  open() { this.yak?.open(); }
90
- close() { this.yak?.close(); }
91
89
  openWithPrompt(prompt: string) { this.yak?.openWithPrompt(prompt); }
90
+ voiceToggle() { return this.yak?.voiceToggle(); }
92
91
  }
93
92
  ```
94
93
 
95
- ### 3. Use in components
94
+ Call `yakService.register(this.yak)` from your root component, then inject `YakService` anywhere:
96
95
 
97
96
  ```ts
98
- // any.component.ts
99
- import { Component, inject } from "@angular/core";
100
- import { YakService } from "./yak.service";
101
-
102
97
  @Component({
103
- template: `
104
- <button (click)="yakService.open()">Open Chat</button>
105
- <p *ngIf="yakService.isOpen()">Chat is open</p>
106
- `,
98
+ template: `<button (click)="yak.open()">Open chat</button>
99
+ <span *ngIf="yak.isOpen()">Chat is open</span>`,
107
100
  })
108
- export class AnyComponent {
109
- yakService = inject(YakService);
101
+ export class HeaderComponent {
102
+ yak = inject(YakService);
110
103
  }
111
104
  ```
112
105
 
113
- ## API Reference
106
+ ## Voice
114
107
 
115
- ### `createYakProvider(options)`
108
+ Set `mode: "voice"` or `mode: "both"`, then drive the session. `voiceStart()` must run from a user gesture (browser mic requirement). Voice state arrives through `subscribeToState` as `state.voiceMachine`:
116
109
 
117
- Creates a Yak widget instance. Returns a `YakApi` object.
110
+ ```ts
111
+ yak.subscribeToState((state) => {
112
+ this.voiceState.set(state.voiceMachine.state); // "idle" | "listening" | "speaking" | ...
113
+ });
114
+ // button handler:
115
+ this.yak.voiceToggle();
116
+ ```
118
117
 
119
- Call `yak.mount()` in `ngOnInit()` and `yak.destroy()` in `ngOnDestroy()`.
118
+ ## Tool events
120
119
 
121
- **Options:**
120
+ ```ts
121
+ yak.subscribeToToolEvents((event) => {
122
+ // { name, args, ok, result?, error? }
123
+ if (event.ok && event.name.startsWith("tasks.")) this.refreshTasks();
124
+ });
125
+ ```
122
126
 
123
- | Option | Type | Description |
124
- |--------|------|-------------|
125
- | `appId` | `string` | Your Yak app ID |
126
- | `getConfig` | `ChatConfigProvider` | Async function returning routes + tools. Called on first open. |
127
- | `onToolCall` | `ToolCallHandler` | Handle tool invocations from the assistant |
128
- | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | Handle GraphQL schema tool calls |
129
- | `onRESTSchemaCall` | `RESTSchemaHandler` | Handle REST/OpenAPI schema tool calls |
130
- | `theme` | `Theme` | Position, color mode, and custom colors |
131
- | `onRedirect` | `(path: string) => void` | Navigation handler (defaults to `window.location.assign`) |
132
- | `disableRestartButton` | `boolean` | Hide the restart session button |
133
- | `trigger` | `boolean \| TriggerButtonConfig` | Built-in trigger button |
127
+ ## API reference
128
+
129
+ ### `createYakProvider(options)`
130
+
131
+ Returns a `YakApi`. Call `yak.mount()` in `ngOnInit()` and `yak.destroy()` in `ngOnDestroy()`.
132
+
133
+ | Option | Type | Default | Description |
134
+ | --- | --- | --- | --- |
135
+ | `appId` | `string` | | Your Yak app ID (required). |
136
+ | `mode` | `"chat" \| "voice" \| "both"` | `"chat"` | Which surfaces the widget exposes. |
137
+ | `trigger` | `boolean \| TriggerButtonConfig` | `false` | Show the floating pill. **Set `true`** to display it; `TriggerButtonConfig` recolors it. |
138
+ | `getConfig` | `ChatConfigProvider` | — | Async provider of routes + tools. Called on open / voice start. |
139
+ | `onToolCall` | `ToolCallHandler` | — | Executes a tool the assistant calls. |
140
+ | `onGraphQLSchemaCall` | `GraphQLSchemaHandler` | — | Handles GraphQL schema tool calls. |
141
+ | `onRESTSchemaCall` | `RESTSchemaHandler` | — | Handles REST/OpenAPI schema tool calls. |
142
+ | `theme` | `Theme` | — | Position, color mode, and colors. |
143
+ | `onRedirect` | `(path: string) => void` | `window.location.assign` | Navigation handler. |
144
+ | `disableRestartButton` | `boolean` | `false` | Hide the restart-session button. |
134
145
 
135
146
  ### `YakApi`
136
147
 
148
+ State (`isOpen`/`isReady`/`voiceMachine`) is read via the `subscribeToState` callback — Angular has no built-in reactive primitive the SDK can return, so wire it into signals or RxJS yourself.
149
+
137
150
  ```ts
151
+ type YakState = {
152
+ isOpen: boolean;
153
+ isReady: boolean;
154
+ chatLoading: boolean;
155
+ voiceMachine: VoiceMachine;
156
+ voiceLoading: boolean;
157
+ };
158
+
138
159
  type YakApi = {
139
- readonly isOpen: boolean; // Plain boolean (use subscribeToState for reactivity)
140
- readonly isReady: boolean; // Plain boolean
160
+ readonly isOpen: boolean; // snapshot use subscribeToState for reactivity
161
+ readonly isReady: boolean; // snapshot
162
+ readonly chatLoading: boolean; // snapshot — isOpen && !isReady
163
+ readonly voiceMachine: VoiceMachine; // snapshot — { state, errorMessage? }
164
+ readonly voiceLoading: boolean; // snapshot — state === "connecting"
141
165
  open: () => void;
142
166
  close: () => void;
143
167
  openWithPrompt: (prompt: string) => void;
168
+ voiceStart: () => Promise<void>;
169
+ voiceStop: () => Promise<void>;
170
+ voiceToggle: () => Promise<void>;
144
171
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
145
- subscribeToState: (handler: (state: { isOpen: boolean; isReady: boolean }) => void) => () => void;
146
- mount: () => void; // Call in ngOnInit() or ngAfterViewInit()
147
- destroy: () => void; // Call in ngOnDestroy()
172
+ subscribeToState: (handler: (state: YakState) => void) => () => void;
173
+ mount: () => void; // call in ngOnInit()
174
+ destroy: () => void; // call in ngOnDestroy()
148
175
  };
149
176
  ```
150
177
 
151
- Use `subscribeToState` to react to state changes — wire it to Angular signals, `BehaviorSubject`s, or change detection:
152
-
153
- ```ts
154
- yak.subscribeToState(({ isOpen, isReady }) => {
155
- this.isOpen.set(isOpen);
156
- this.changeDetector.markForCheck();
157
- });
158
- ```
159
-
160
178
  ## Logging
161
179
 
162
180
  ```ts
163
181
  import { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/angular";
164
182
 
165
- enableYakLogging(); // Enable verbose SDK logs
166
- disableYakLogging(); // Disable SDK logs
167
- isYakLoggingEnabled(); // → boolean
183
+ enableYakLogging(); // verbose SDK logs
168
184
  ```
169
185
 
170
186
  ## Types
@@ -173,16 +189,19 @@ isYakLoggingEnabled(); // → boolean
173
189
  import type {
174
190
  YakProviderOptions,
175
191
  YakApi,
192
+ YakState,
176
193
  ToolCallEventHandler,
177
194
  ChatConfigProvider,
178
195
  ToolCallHandler,
179
196
  ToolCallEvent,
180
197
  Theme,
181
- TriggerButtonConfig,
198
+ WidgetMode,
182
199
  WidgetPosition,
200
+ VoiceState,
201
+ VoiceMachine,
183
202
  } from "@yak-io/angular";
184
203
  ```
185
204
 
186
205
  ## License
187
206
 
188
- Proprietary — see LICENSE file.
207
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ export type { ChatConfigProvider, GraphQLRequest, GraphQLSchemaHandler, GraphQLSchemaSource, OpenAPISchemaSource, RESTRequest, RESTSchemaHandler, SchemaSource, Theme, ThemeColors, ToolCallEvent, ToolCallHandler, TriggerButtonConfig, VoiceMachine, VoiceState, WidgetMode, WidgetPosition, } from "@yak-io/javascript";
2
+ export { disableYakLogging, enableYakLogging, isYakLoggingEnabled } from "@yak-io/javascript";
3
+ export type { ToolCallEventHandler, YakApi, YakProviderOptions, YakState, } from "./service.js";
1
4
  export { createYakProvider } from "./service.js";
2
- export type { YakProviderOptions, YakApi, ToolCallEventHandler } from "./service.js";
3
- export { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/javascript";
4
- export type { GraphQLSchemaHandler, RESTSchemaHandler, GraphQLRequest, RESTRequest, ToolCallHandler, ToolCallEvent, SchemaSource, GraphQLSchemaSource, OpenAPISchemaSource, Theme, ThemeColors, TriggerButtonConfig, WidgetPosition, ChatConfigProvider, } from "@yak-io/javascript";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGrF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9F,YAAY,EACV,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,EACL,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,KAAK,EACL,WAAW,EACX,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,UAAU,EACV,cAAc,GACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9F,YAAY,EACV,oBAAoB,EACpB,MAAM,EACN,kBAAkB,EAClB,QAAQ,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // Public API
2
- export { createYakProvider } from "./service.js";
3
2
  // Re-export logging utilities
4
- export { enableYakLogging, disableYakLogging, isYakLoggingEnabled } from "@yak-io/javascript";
3
+ export { disableYakLogging, enableYakLogging, isYakLoggingEnabled } from "@yak-io/javascript";
4
+ export { createYakProvider } from "./service.js";
package/dist/service.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { type TriggerButtonConfig, type ChatConfigProvider, type ToolCallHandler, type ToolCallEvent, type GraphQLSchemaHandler, type RESTSchemaHandler, type Theme } from "@yak-io/javascript";
1
+ import { type ChatConfigProvider, type GraphQLSchemaHandler, type RESTSchemaHandler, type Theme, type ToolCallEvent, type ToolCallHandler, type TriggerButtonConfig, type VoiceMachine, type WidgetMode } from "@yak-io/javascript";
2
2
  export type ToolCallEventHandler = (event: ToolCallEvent) => void;
3
3
  export type YakProviderOptions = {
4
4
  appId: string;
5
+ mode?: WidgetMode;
5
6
  getConfig?: ChatConfigProvider;
6
7
  onToolCall?: ToolCallHandler;
7
8
  onGraphQLSchemaCall?: GraphQLSchemaHandler;
@@ -11,51 +12,49 @@ export type YakProviderOptions = {
11
12
  disableRestartButton?: boolean;
12
13
  trigger?: boolean | TriggerButtonConfig;
13
14
  };
15
+ export type YakState = {
16
+ isOpen: boolean;
17
+ isReady: boolean;
18
+ chatLoading: boolean;
19
+ voiceMachine: VoiceMachine;
20
+ voiceLoading: boolean;
21
+ };
22
+ /** Handle for controlling the Yak widget — chat + voice — from Angular. */
14
23
  export type YakApi = {
15
- /** Whether the chat widget is open */
24
+ /** Whether the chat panel is currently open. */
16
25
  readonly isOpen: boolean;
17
- /** Whether the iframe is ready */
26
+ /** Whether the chat iframe is ready to receive messages. */
18
27
  readonly isReady: boolean;
19
- /** Open the chat widget */
28
+ /** Whether the chat is opening but not yet interactive (`isOpen && !isReady`). */
29
+ readonly chatLoading: boolean;
30
+ /** Current voice state-machine snapshot. `idle` when mode is `chat`. */
31
+ readonly voiceMachine: VoiceMachine;
32
+ /** Whether the voice session is establishing its connection (`state === "connecting"`). */
33
+ readonly voiceLoading: boolean;
34
+ /** Open the chat panel. */
20
35
  open: () => void;
21
- /** Close the chat widget */
36
+ /** Close the chat panel. */
22
37
  close: () => void;
23
- /** Open the chat widget and send a prompt */
38
+ /** Open the chat panel and send a specific prompt. */
24
39
  openWithPrompt: (prompt: string) => void;
25
- /** Subscribe to tool call completion events. Returns an unsubscribe function. */
40
+ /** Start a voice session. Must be invoked from a user gesture. */
41
+ voiceStart: () => Promise<void>;
42
+ /** Stop the current voice session. */
43
+ voiceStop: () => Promise<void>;
44
+ /** Toggle voice: start if idle/error, stop if active. */
45
+ voiceToggle: () => Promise<void>;
46
+ /** Subscribe to tool-call completion events; returns an unsubscribe function. */
26
47
  subscribeToToolEvents: (handler: ToolCallEventHandler) => () => void;
27
- /** Subscribe to state changes. Returns an unsubscribe function. */
28
- subscribeToState: (handler: (state: {
29
- isOpen: boolean;
30
- isReady: boolean;
31
- }) => void) => () => void;
32
- /** Mount the widget DOM — call in ngOnInit or ngAfterViewInit */
48
+ /** Subscribe to chat + voice state changes. */
49
+ subscribeToState: (handler: (state: YakState) => void) => () => void;
50
+ /** Mount the widget into the DOM. */
33
51
  mount: () => void;
34
- /** Destroy the widget DOM call in ngOnDestroy */
52
+ /** Tear down the widget and remove its listeners. */
35
53
  destroy: () => void;
36
54
  };
37
55
  /**
38
- * Creates a yak chat widget instance for Angular.
39
- * Use in an Angular service or component — call `mount()` in `ngOnInit`
40
- * and `destroy()` in `ngOnDestroy`.
41
- *
42
- * @example
43
- * ```ts
44
- * import { Component, OnInit, OnDestroy } from "@angular/core";
45
- * import { createYakProvider, type YakApi } from "@yak-io/angular";
46
- *
47
- * @Component({ selector: "app-root", template: `...` })
48
- * export class AppComponent implements OnInit, OnDestroy {
49
- * private yak: YakApi;
50
- *
51
- * constructor() {
52
- * this.yak = createYakProvider({ appId: "my-app" });
53
- * }
54
- *
55
- * ngOnInit() { this.yak.mount(); }
56
- * ngOnDestroy() { this.yak.destroy(); }
57
- * }
58
- * ```
56
+ * Creates a yak widget (chat + voice) for Angular.
57
+ * Call `mount()` in `ngOnInit` and `destroy()` in `ngOnDestroy`.
59
58
  */
60
59
  export declare function createYakProvider(options: YakProviderOptions): YakApi;
61
60
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACX,MAAM,oBAAoB,CAAC;AAK5B,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,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,sCAAsC;IACtC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,6CAA6C;IAC7C,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,iFAAiF;IACjF,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IACrE,mEAAmE;IACnE,gBAAgB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAClG,iEAAiE;IACjE,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,mDAAmD;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAoGrE"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.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;AAI5B,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,QAAQ,GAAG;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,MAAM,GAAG;IACnB,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,2FAA2F;IAC3F,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,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,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;IACjC,iFAAiF;IACjF,qBAAqB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,MAAM,IAAI,CAAC;IACrE,+CAA+C;IAC/C,gBAAgB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IACrE,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,CAyIrE"}
package/dist/service.js CHANGED
@@ -1,34 +1,32 @@
1
- import { YakEmbed, } from "@yak-io/javascript";
2
- import { logger } from "@yak-io/javascript";
1
+ import { INITIAL_VOICE_MACHINE, logger, YakEmbed, } from "@yak-io/javascript";
3
2
  // ── Provider factory ────────────────────────────────────────────────────────
4
3
  /**
5
- * Creates a yak chat widget instance for Angular.
6
- * Use in an Angular service or component — call `mount()` in `ngOnInit`
7
- * and `destroy()` in `ngOnDestroy`.
8
- *
9
- * @example
10
- * ```ts
11
- * import { Component, OnInit, OnDestroy } from "@angular/core";
12
- * import { createYakProvider, type YakApi } from "@yak-io/angular";
13
- *
14
- * @Component({ selector: "app-root", template: `...` })
15
- * export class AppComponent implements OnInit, OnDestroy {
16
- * private yak: YakApi;
17
- *
18
- * constructor() {
19
- * this.yak = createYakProvider({ appId: "my-app" });
20
- * }
21
- *
22
- * ngOnInit() { this.yak.mount(); }
23
- * ngOnDestroy() { this.yak.destroy(); }
24
- * }
25
- * ```
4
+ * Creates a yak widget (chat + voice) for Angular.
5
+ * Call `mount()` in `ngOnInit` and `destroy()` in `ngOnDestroy`.
26
6
  */
27
7
  export function createYakProvider(options) {
28
8
  let _isOpen = false;
29
9
  let _isReady = false;
10
+ let _voiceMachine = INITIAL_VOICE_MACHINE;
30
11
  const toolEventSubscribers = new Set();
31
12
  const stateSubscribers = new Set();
13
+ const notifyState = () => {
14
+ const snap = {
15
+ isOpen: _isOpen,
16
+ isReady: _isReady,
17
+ chatLoading: _isOpen && !_isReady,
18
+ voiceMachine: _voiceMachine,
19
+ voiceLoading: _voiceMachine.state === "connecting",
20
+ };
21
+ for (const subscriber of stateSubscribers) {
22
+ try {
23
+ subscriber(snap);
24
+ }
25
+ catch (err) {
26
+ logger.warn("Error in state subscriber:", err);
27
+ }
28
+ }
29
+ };
32
30
  const handleToolCallComplete = (event) => {
33
31
  logger.debug("Tool call completed, notifying subscribers:", {
34
32
  name: event.name,
@@ -48,8 +46,10 @@ export function createYakProvider(options) {
48
46
  (typeof window !== "undefined" ? (path) => window.location.assign(path) : undefined);
49
47
  const embed = new YakEmbed({
50
48
  appId: options.appId,
49
+ mode: options.mode,
51
50
  theme: options.theme,
52
51
  trigger: options.trigger ?? false,
52
+ getConfig: options.getConfig,
53
53
  onToolCall: options.onToolCall,
54
54
  onGraphQLSchemaCall: options.onGraphQLSchemaCall,
55
55
  onRESTSchemaCall: options.onRESTSchemaCall,
@@ -57,18 +57,14 @@ export function createYakProvider(options) {
57
57
  options: { disableRestartButton: options.disableRestartButton },
58
58
  onToolCallComplete: handleToolCallComplete,
59
59
  });
60
- // Sync embed state
61
60
  embed.onStateChange((state) => {
62
61
  _isOpen = state.isOpen;
63
62
  _isReady = state.isReady;
64
- for (const subscriber of stateSubscribers) {
65
- try {
66
- subscriber({ isOpen: _isOpen, isReady: _isReady });
67
- }
68
- catch (err) {
69
- logger.warn("Error in state subscriber:", err);
70
- }
71
- }
63
+ notifyState();
64
+ });
65
+ embed.onVoiceStateChange((m) => {
66
+ _voiceMachine = m;
67
+ notifyState();
72
68
  });
73
69
  // Fetch chat config on first open
74
70
  if (options.getConfig) {
@@ -90,6 +86,14 @@ export function createYakProvider(options) {
90
86
  }
91
87
  });
92
88
  }
89
+ const voiceStart = async () => {
90
+ try {
91
+ await embed.voiceStart();
92
+ }
93
+ catch (err) {
94
+ logger.warn("Voice start failed", err);
95
+ }
96
+ };
93
97
  return {
94
98
  get isOpen() {
95
99
  return _isOpen;
@@ -97,9 +101,21 @@ export function createYakProvider(options) {
97
101
  get isReady() {
98
102
  return _isReady;
99
103
  },
104
+ get chatLoading() {
105
+ return _isOpen && !_isReady;
106
+ },
107
+ get voiceMachine() {
108
+ return _voiceMachine;
109
+ },
110
+ get voiceLoading() {
111
+ return _voiceMachine.state === "connecting";
112
+ },
100
113
  open: () => embed.open(),
101
114
  close: () => embed.close(),
102
115
  openWithPrompt: (prompt) => embed.openWithPrompt(prompt),
116
+ voiceStart,
117
+ voiceStop: () => embed.voiceStop(),
118
+ voiceToggle: () => embed.voiceToggle(),
103
119
  subscribeToToolEvents: (handler) => {
104
120
  toolEventSubscribers.add(handler);
105
121
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yak-io/angular",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Angular SDK 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,16 +42,17 @@
41
42
  "./package.json": "./package.json"
42
43
  },
43
44
  "dependencies": {
44
- "@yak-io/javascript": "0.7.0"
45
+ "@yak-io/javascript": "0.9.0"
45
46
  },
46
47
  "peerDependencies": {
47
48
  "@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0"
48
49
  },
49
50
  "devDependencies": {
50
- "@types/node": "^24.12.0",
51
+ "@types/node": "^24.12.4",
51
52
  "typescript": "^5.3.0",
52
53
  "@repo/typescript-config": "0.0.0"
53
54
  },
55
+ "homepage": "https://docs.yak.io/docs/sdks/angular",
54
56
  "scripts": {
55
57
  "build": "tsc",
56
58
  "check-types": "tsc --noEmit",