@tanstack/ai 0.0.2 → 0.0.3

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.
@@ -277,35 +277,8 @@ export interface AIDevtoolsEventMap {
277
277
  timestamp: number;
278
278
  };
279
279
  }
280
- type StripPrefix<T extends string> = T extends `tanstack-ai-devtools:${infer Suffix}` ? Suffix : never;
281
- type EventSuffix = StripPrefix<keyof AIDevtoolsEventMap & string>;
282
280
  declare class AiEventClient extends EventClient<AIDevtoolsEventMap> {
283
- private eventTarget;
284
281
  constructor();
285
- /**
286
- * Subscribe to events using both the parent EventClient and EventTarget API
287
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
288
- * @param handler - The event handler function
289
- * @param options - Optional configuration for event subscription
290
- * @returns A function to unsubscribe from the event
291
- */
292
- on<TSuffix extends EventSuffix>(eventSuffix: TSuffix, handler: (event: {
293
- type: `tanstack-ai-devtools:${TSuffix}`;
294
- payload: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`];
295
- }) => void, options?: {
296
- withEventTarget?: boolean;
297
- }): () => void;
298
- /**
299
- * Emit an event to both the parent EventClient and the EventTarget
300
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
301
- * @param data - The event data
302
- */
303
- emit<TSuffix extends EventSuffix>(eventSuffix: TSuffix, data: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`]): void;
304
- /**
305
- * Get the underlying EventTarget for advanced use cases
306
- * @returns The EventTarget instance
307
- */
308
- getEventTarget(): EventTarget;
309
282
  }
310
283
  declare const aiEventClient: AiEventClient;
311
284
  export { aiEventClient };
@@ -4,55 +4,6 @@ class AiEventClient extends EventClient {
4
4
  super({
5
5
  pluginId: "tanstack-ai-devtools"
6
6
  });
7
- this.eventTarget = new EventTarget();
8
- }
9
- /**
10
- * Subscribe to events using both the parent EventClient and EventTarget API
11
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
12
- * @param handler - The event handler function
13
- * @param options - Optional configuration for event subscription
14
- * @returns A function to unsubscribe from the event
15
- */
16
- on(eventSuffix, handler, options) {
17
- const parentUnsubscribe = super.on(eventSuffix, handler);
18
- const withEventTarget = options?.withEventTarget ?? true;
19
- let eventListener;
20
- if (withEventTarget) {
21
- eventListener = (event) => {
22
- if (event instanceof CustomEvent) {
23
- handler({
24
- type: `${eventSuffix}`,
25
- payload: event.detail
26
- });
27
- }
28
- };
29
- this.eventTarget.addEventListener(eventSuffix, eventListener);
30
- }
31
- return () => {
32
- parentUnsubscribe();
33
- if (withEventTarget && eventListener) {
34
- this.eventTarget.removeEventListener(eventSuffix, eventListener);
35
- }
36
- };
37
- }
38
- /**
39
- * Emit an event to both the parent EventClient and the EventTarget
40
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
41
- * @param data - The event data
42
- */
43
- emit(eventSuffix, data) {
44
- super.emit(eventSuffix, data);
45
- const customEvent = new CustomEvent(eventSuffix, {
46
- detail: data
47
- });
48
- this.eventTarget.dispatchEvent(customEvent);
49
- }
50
- /**
51
- * Get the underlying EventTarget for advanced use cases
52
- * @returns The EventTarget instance
53
- */
54
- getEventTarget() {
55
- return this.eventTarget;
56
7
  }
57
8
  }
58
9
  const aiEventClient = new AiEventClient();
@@ -1 +1 @@
1
- {"version":3,"file":"event-client.js","sources":["../../src/event-client.ts"],"sourcesContent":["import { EventClient } from '@tanstack/devtools-event-client'\n\n/**\n * Tool call states - track the lifecycle of a tool call\n * Must match @tanstack/ai-client ToolCallState\n */\ntype ToolCallState =\n | 'awaiting-input' // Received start but no arguments yet\n | 'input-streaming' // Partial arguments received\n | 'input-complete' // All arguments received\n | 'approval-requested' // Waiting for user approval\n | 'approval-responded' // User has approved/denied\n\n/**\n * Tool result states - track the lifecycle of a tool result\n * Must match @tanstack/ai-client ToolResultState\n */\ntype ToolResultState =\n | 'streaming' // Placeholder for future streamed output\n | 'complete' // Result is complete\n | 'error' // Error occurred\n\nexport interface AIDevtoolsEventMap {\n // AI Stream events - from @tanstack/ai package\n 'tanstack-ai-devtools:stream:started': {\n streamId: string\n model: string\n provider: string\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:stream:chunk:content': {\n streamId: string\n messageId?: string\n content: string\n delta?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:tool-call': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n index: number\n arguments: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:tool-result': {\n streamId: string\n messageId?: string\n toolCallId: string\n result: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:done': {\n streamId: string\n messageId?: string\n finishReason: string | null\n usage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:error': {\n streamId: string\n messageId?: string\n error: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:thinking': {\n streamId: string\n messageId?: string\n content: string\n delta?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:approval-requested': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:tool-input-available': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n input: any\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:call-completed': {\n requestId: string\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n result: any\n duration: number\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:ended': {\n requestId: string\n streamId: string\n totalChunks: number\n duration: number\n timestamp: number\n }\n 'tanstack-ai-devtools:chat:started': {\n requestId: string\n streamId: string\n provider: string\n model: string\n messageCount: number\n hasTools: boolean\n streaming: boolean\n timestamp: number\n clientId?: string\n toolNames?: Array<string>\n options?: Record<string, unknown>\n providerOptions?: Record<string, unknown>\n }\n 'tanstack-ai-devtools:chat:completed': {\n requestId: string\n streamId: string\n model: string\n content: string\n messageId?: string\n finishReason?: string\n usage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n 'tanstack-ai-devtools:chat:iteration': {\n requestId: string\n streamId: string\n iterationNumber: number\n messageCount: number\n toolCallCount: number\n timestamp: number\n }\n 'tanstack-ai-devtools:usage:tokens': {\n requestId: string\n streamId: string\n model: string\n messageId?: string\n usage: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n\n // Embedding events\n 'tanstack-ai-devtools:embedding:started': {\n requestId: string\n model: string\n inputCount: number\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:embedding:completed': {\n requestId: string\n model: string\n inputCount: number\n duration: number\n timestamp: number\n }\n\n // Summarize events\n 'tanstack-ai-devtools:summarize:started': {\n requestId: string\n model: string\n inputLength: number\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:summarize:completed': {\n requestId: string\n model: string\n inputLength: number\n outputLength: number\n duration: number\n timestamp: number\n }\n\n // Chat Client events - from @tanstack/ai-client package\n 'tanstack-ai-devtools:client:created': {\n clientId: string\n initialMessageCount: number\n timestamp: number\n }\n 'tanstack-ai-devtools:client:message-appended': {\n clientId: string\n messageId: string\n role: 'user' | 'assistant' | 'system' | 'tool'\n contentPreview: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:message-sent': {\n clientId: string\n messageId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:loading-changed': {\n clientId: string\n isLoading: boolean\n timestamp: number\n }\n 'tanstack-ai-devtools:client:error-changed': {\n clientId: string\n error: string | null\n timestamp: number\n }\n 'tanstack-ai-devtools:client:messages-cleared': {\n clientId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:reloaded': {\n clientId: string\n fromMessageIndex: number\n timestamp: number\n }\n 'tanstack-ai-devtools:client:stopped': {\n clientId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:result-added': {\n clientId: string\n toolCallId: string\n toolName: string\n output: any\n state: 'output-available' | 'output-error'\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:approval-responded': {\n clientId: string\n approvalId: string\n toolCallId: string\n approved: boolean\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:text-updated': {\n streamId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:tool-call-state-changed': {\n streamId: string\n toolCallId: string\n toolName: string\n state: ToolCallState\n arguments: any\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:tool-result-state-changed': {\n streamId: string\n toolCallId: string\n content: any\n state: ToolResultState\n error?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:assistant-message-updated': {\n clientId: string\n messageId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:tool-call-updated': {\n clientId: string\n messageId: string\n toolCallId: string\n toolName: string\n state: ToolCallState\n arguments: any\n timestamp: number\n }\n 'tanstack-ai-devtools:client:approval-requested': {\n clientId: string\n messageId: string\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n timestamp: number\n }\n}\n\n// Helper type to strip the prefix at the type level\ntype StripPrefix<T extends string> =\n T extends `tanstack-ai-devtools:${infer Suffix}` ? Suffix : never\n\n// Get all event names without the prefix\ntype EventSuffix = StripPrefix<keyof AIDevtoolsEventMap & string>\n\nclass AiEventClient extends EventClient<AIDevtoolsEventMap> {\n private eventTarget: EventTarget\n\n constructor() {\n super({\n pluginId: 'tanstack-ai-devtools',\n })\n this.eventTarget = new EventTarget()\n }\n\n /**\n * Subscribe to events using both the parent EventClient and EventTarget API\n * @param eventSuffix - The event name without the prefix (e.g., \"stream:started\")\n * @param handler - The event handler function\n * @param options - Optional configuration for event subscription\n * @returns A function to unsubscribe from the event\n */\n override on<TSuffix extends EventSuffix>(\n eventSuffix: TSuffix,\n handler: (event: {\n type: `tanstack-ai-devtools:${TSuffix}`\n payload: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`]\n }) => void,\n options?: { withEventTarget?: boolean },\n ): () => void {\n const parentUnsubscribe = super.on(eventSuffix, handler)\n\n const withEventTarget = options?.withEventTarget ?? true\n let eventListener: ((event: Event) => void) | undefined\n\n if (withEventTarget) {\n // Create a wrapper to handle CustomEvent for EventTarget\n eventListener = (event: Event) => {\n if (event instanceof CustomEvent) {\n handler({\n type: `${eventSuffix}` as `tanstack-ai-devtools:${TSuffix}`,\n payload: event.detail,\n })\n }\n }\n\n // Add listener to EventTarget\n this.eventTarget.addEventListener(eventSuffix, eventListener)\n }\n\n // Return unsubscribe function that cleans up both subscriptions\n return () => {\n parentUnsubscribe()\n if (withEventTarget && eventListener) {\n this.eventTarget.removeEventListener(eventSuffix, eventListener)\n }\n }\n }\n\n /**\n * Emit an event to both the parent EventClient and the EventTarget\n * @param eventSuffix - The event name without the prefix (e.g., \"stream:started\")\n * @param data - The event data\n */\n override emit<TSuffix extends EventSuffix>(\n eventSuffix: TSuffix,\n data: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`],\n ): void {\n super.emit(eventSuffix, data)\n\n // Always dispatch to EventTarget (for local listeners)\n const customEvent = new CustomEvent(eventSuffix, {\n detail: data,\n })\n this.eventTarget.dispatchEvent(customEvent)\n }\n\n /**\n * Get the underlying EventTarget for advanced use cases\n * @returns The EventTarget instance\n */\n getEventTarget(): EventTarget {\n return this.eventTarget\n }\n}\n\nconst aiEventClient = new AiEventClient()\n\nexport { aiEventClient }\n"],"names":[],"mappings":";AAiTA,MAAM,sBAAsB,YAAgC;AAAA,EAG1D,cAAc;AACZ,UAAM;AAAA,MACJ,UAAU;AAAA,IAAA,CACX;AACD,SAAK,cAAc,IAAI,YAAA;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASS,GACP,aACA,SAIA,SACY;AACZ,UAAM,oBAAoB,MAAM,GAAG,aAAa,OAAO;AAEvD,UAAM,kBAAkB,SAAS,mBAAmB;AACpD,QAAI;AAEJ,QAAI,iBAAiB;AAEnB,sBAAgB,CAAC,UAAiB;AAChC,YAAI,iBAAiB,aAAa;AAChC,kBAAQ;AAAA,YACN,MAAM,GAAG,WAAW;AAAA,YACpB,SAAS,MAAM;AAAA,UAAA,CAChB;AAAA,QACH;AAAA,MACF;AAGA,WAAK,YAAY,iBAAiB,aAAa,aAAa;AAAA,IAC9D;AAGA,WAAO,MAAM;AACX,wBAAA;AACA,UAAI,mBAAmB,eAAe;AACpC,aAAK,YAAY,oBAAoB,aAAa,aAAa;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,KACP,aACA,MACM;AACN,UAAM,KAAK,aAAa,IAAI;AAG5B,UAAM,cAAc,IAAI,YAAY,aAAa;AAAA,MAC/C,QAAQ;AAAA,IAAA,CACT;AACD,SAAK,YAAY,cAAc,WAAW;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AACF;AAEA,MAAM,gBAAgB,IAAI,cAAA;"}
1
+ {"version":3,"file":"event-client.js","sources":["../../src/event-client.ts"],"sourcesContent":["import { EventClient } from '@tanstack/devtools-event-client'\n\n/**\n * Tool call states - track the lifecycle of a tool call\n * Must match @tanstack/ai-client ToolCallState\n */\ntype ToolCallState =\n | 'awaiting-input' // Received start but no arguments yet\n | 'input-streaming' // Partial arguments received\n | 'input-complete' // All arguments received\n | 'approval-requested' // Waiting for user approval\n | 'approval-responded' // User has approved/denied\n\n/**\n * Tool result states - track the lifecycle of a tool result\n * Must match @tanstack/ai-client ToolResultState\n */\ntype ToolResultState =\n | 'streaming' // Placeholder for future streamed output\n | 'complete' // Result is complete\n | 'error' // Error occurred\n\nexport interface AIDevtoolsEventMap {\n // AI Stream events - from @tanstack/ai package\n 'tanstack-ai-devtools:stream:started': {\n streamId: string\n model: string\n provider: string\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:stream:chunk:content': {\n streamId: string\n messageId?: string\n content: string\n delta?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:tool-call': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n index: number\n arguments: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:tool-result': {\n streamId: string\n messageId?: string\n toolCallId: string\n result: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:done': {\n streamId: string\n messageId?: string\n finishReason: string | null\n usage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:error': {\n streamId: string\n messageId?: string\n error: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:chunk:thinking': {\n streamId: string\n messageId?: string\n content: string\n delta?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:approval-requested': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:tool-input-available': {\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n input: any\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:call-completed': {\n requestId: string\n streamId: string\n messageId?: string\n toolCallId: string\n toolName: string\n result: any\n duration: number\n timestamp: number\n }\n 'tanstack-ai-devtools:stream:ended': {\n requestId: string\n streamId: string\n totalChunks: number\n duration: number\n timestamp: number\n }\n 'tanstack-ai-devtools:chat:started': {\n requestId: string\n streamId: string\n provider: string\n model: string\n messageCount: number\n hasTools: boolean\n streaming: boolean\n timestamp: number\n clientId?: string\n toolNames?: Array<string>\n options?: Record<string, unknown>\n providerOptions?: Record<string, unknown>\n }\n 'tanstack-ai-devtools:chat:completed': {\n requestId: string\n streamId: string\n model: string\n content: string\n messageId?: string\n finishReason?: string\n usage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n 'tanstack-ai-devtools:chat:iteration': {\n requestId: string\n streamId: string\n iterationNumber: number\n messageCount: number\n toolCallCount: number\n timestamp: number\n }\n 'tanstack-ai-devtools:usage:tokens': {\n requestId: string\n streamId: string\n model: string\n messageId?: string\n usage: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n }\n timestamp: number\n }\n\n // Embedding events\n 'tanstack-ai-devtools:embedding:started': {\n requestId: string\n model: string\n inputCount: number\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:embedding:completed': {\n requestId: string\n model: string\n inputCount: number\n duration: number\n timestamp: number\n }\n\n // Summarize events\n 'tanstack-ai-devtools:summarize:started': {\n requestId: string\n model: string\n inputLength: number\n timestamp: number\n clientId?: string\n }\n 'tanstack-ai-devtools:summarize:completed': {\n requestId: string\n model: string\n inputLength: number\n outputLength: number\n duration: number\n timestamp: number\n }\n\n // Chat Client events - from @tanstack/ai-client package\n 'tanstack-ai-devtools:client:created': {\n clientId: string\n initialMessageCount: number\n timestamp: number\n }\n 'tanstack-ai-devtools:client:message-appended': {\n clientId: string\n messageId: string\n role: 'user' | 'assistant' | 'system' | 'tool'\n contentPreview: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:message-sent': {\n clientId: string\n messageId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:loading-changed': {\n clientId: string\n isLoading: boolean\n timestamp: number\n }\n 'tanstack-ai-devtools:client:error-changed': {\n clientId: string\n error: string | null\n timestamp: number\n }\n 'tanstack-ai-devtools:client:messages-cleared': {\n clientId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:reloaded': {\n clientId: string\n fromMessageIndex: number\n timestamp: number\n }\n 'tanstack-ai-devtools:client:stopped': {\n clientId: string\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:result-added': {\n clientId: string\n toolCallId: string\n toolName: string\n output: any\n state: 'output-available' | 'output-error'\n timestamp: number\n }\n 'tanstack-ai-devtools:tool:approval-responded': {\n clientId: string\n approvalId: string\n toolCallId: string\n approved: boolean\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:text-updated': {\n streamId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:tool-call-state-changed': {\n streamId: string\n toolCallId: string\n toolName: string\n state: ToolCallState\n arguments: any\n timestamp: number\n }\n 'tanstack-ai-devtools:processor:tool-result-state-changed': {\n streamId: string\n toolCallId: string\n content: any\n state: ToolResultState\n error?: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:assistant-message-updated': {\n clientId: string\n messageId: string\n content: string\n timestamp: number\n }\n 'tanstack-ai-devtools:client:tool-call-updated': {\n clientId: string\n messageId: string\n toolCallId: string\n toolName: string\n state: ToolCallState\n arguments: any\n timestamp: number\n }\n 'tanstack-ai-devtools:client:approval-requested': {\n clientId: string\n messageId: string\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n timestamp: number\n }\n}\n\nclass AiEventClient extends EventClient<AIDevtoolsEventMap> {\n constructor() {\n super({\n pluginId: 'tanstack-ai-devtools',\n })\n }\n}\n\nconst aiEventClient = new AiEventClient()\n\nexport { aiEventClient }\n"],"names":[],"mappings":";AA0SA,MAAM,sBAAsB,YAAgC;AAAA,EAC1D,cAAc;AACZ,UAAM;AAAA,MACJ,UAAU;AAAA,IAAA,CACX;AAAA,EACH;AACF;AAEA,MAAM,gBAAgB,IAAI,cAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Core TanStack AI library - Open source AI SDK",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "embeddings"
40
40
  ],
41
41
  "dependencies": {
42
- "@tanstack/devtools-event-client": "^0.3.5",
42
+ "@tanstack/devtools-event-client": "^0.4.0",
43
43
  "partial-json": "^0.1.7"
44
44
  },
45
45
  "peerDependencies": {
@@ -296,91 +296,11 @@ export interface AIDevtoolsEventMap {
296
296
  }
297
297
  }
298
298
 
299
- // Helper type to strip the prefix at the type level
300
- type StripPrefix<T extends string> =
301
- T extends `tanstack-ai-devtools:${infer Suffix}` ? Suffix : never
302
-
303
- // Get all event names without the prefix
304
- type EventSuffix = StripPrefix<keyof AIDevtoolsEventMap & string>
305
-
306
299
  class AiEventClient extends EventClient<AIDevtoolsEventMap> {
307
- private eventTarget: EventTarget
308
-
309
300
  constructor() {
310
301
  super({
311
302
  pluginId: 'tanstack-ai-devtools',
312
303
  })
313
- this.eventTarget = new EventTarget()
314
- }
315
-
316
- /**
317
- * Subscribe to events using both the parent EventClient and EventTarget API
318
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
319
- * @param handler - The event handler function
320
- * @param options - Optional configuration for event subscription
321
- * @returns A function to unsubscribe from the event
322
- */
323
- override on<TSuffix extends EventSuffix>(
324
- eventSuffix: TSuffix,
325
- handler: (event: {
326
- type: `tanstack-ai-devtools:${TSuffix}`
327
- payload: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`]
328
- }) => void,
329
- options?: { withEventTarget?: boolean },
330
- ): () => void {
331
- const parentUnsubscribe = super.on(eventSuffix, handler)
332
-
333
- const withEventTarget = options?.withEventTarget ?? true
334
- let eventListener: ((event: Event) => void) | undefined
335
-
336
- if (withEventTarget) {
337
- // Create a wrapper to handle CustomEvent for EventTarget
338
- eventListener = (event: Event) => {
339
- if (event instanceof CustomEvent) {
340
- handler({
341
- type: `${eventSuffix}` as `tanstack-ai-devtools:${TSuffix}`,
342
- payload: event.detail,
343
- })
344
- }
345
- }
346
-
347
- // Add listener to EventTarget
348
- this.eventTarget.addEventListener(eventSuffix, eventListener)
349
- }
350
-
351
- // Return unsubscribe function that cleans up both subscriptions
352
- return () => {
353
- parentUnsubscribe()
354
- if (withEventTarget && eventListener) {
355
- this.eventTarget.removeEventListener(eventSuffix, eventListener)
356
- }
357
- }
358
- }
359
-
360
- /**
361
- * Emit an event to both the parent EventClient and the EventTarget
362
- * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
363
- * @param data - The event data
364
- */
365
- override emit<TSuffix extends EventSuffix>(
366
- eventSuffix: TSuffix,
367
- data: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`],
368
- ): void {
369
- super.emit(eventSuffix, data)
370
-
371
- // Always dispatch to EventTarget (for local listeners)
372
- const customEvent = new CustomEvent(eventSuffix, {
373
- detail: data,
374
- })
375
- this.eventTarget.dispatchEvent(customEvent)
376
- }
377
-
378
- /**
379
- * Get the underlying EventTarget for advanced use cases
380
- * @returns The EventTarget instance
381
- */
382
- getEventTarget(): EventTarget {
383
- return this.eventTarget
384
304
  }
385
305
  }
386
306