@tinkrapp/widget 1.0.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/dist/client-CExUGn7b.d.cts +147 -0
- package/dist/client-CExUGn7b.d.ts +147 -0
- package/dist/course-ai-widget.css +2 -0
- package/dist/course-ai-widget.css.map +1 -0
- package/dist/course-ai-widget.global.js +632 -0
- package/dist/course-ai-widget.global.js.map +1 -0
- package/dist/index.cjs +233 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +4857 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +165 -0
- package/dist/react.d.ts +165 -0
- package/dist/react.js +4815 -0
- package/dist/react.js.map +1 -0
- package/package.json +104 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/events.ts
|
|
4
|
+
var TypedEventEmitter = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
7
|
+
}
|
|
8
|
+
on(event, handler) {
|
|
9
|
+
if (!this.listeners.has(event)) {
|
|
10
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
11
|
+
}
|
|
12
|
+
this.listeners.get(event).add(handler);
|
|
13
|
+
return () => this.off(event, handler);
|
|
14
|
+
}
|
|
15
|
+
off(event, handler) {
|
|
16
|
+
this.listeners.get(event)?.delete(handler);
|
|
17
|
+
}
|
|
18
|
+
emit(event, payload) {
|
|
19
|
+
this.listeners.get(event)?.forEach((handler) => {
|
|
20
|
+
try {
|
|
21
|
+
handler(payload);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error(`Error in ${String(event)} handler:`, error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this.listeners.clear();
|
|
29
|
+
}
|
|
30
|
+
removeAllListeners(event) {
|
|
31
|
+
if (event) {
|
|
32
|
+
this.listeners.delete(event);
|
|
33
|
+
} else {
|
|
34
|
+
this.listeners.clear();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/core/api.ts
|
|
40
|
+
var WidgetAPI = class {
|
|
41
|
+
constructor(config) {
|
|
42
|
+
this.config = {
|
|
43
|
+
baseUrl: "http://localhost:3000",
|
|
44
|
+
userId: "",
|
|
45
|
+
debug: false,
|
|
46
|
+
assistantId: config.apiKey,
|
|
47
|
+
// Default to apiKey for backwards compatibility
|
|
48
|
+
...config
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async createSession() {
|
|
52
|
+
const response = await this.request("/sessions", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
// apiKey IS the assistantId
|
|
56
|
+
assistantId: this.config.apiKey,
|
|
57
|
+
userId: this.config.userId
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
async sendMessage(sessionId, content) {
|
|
63
|
+
const response = await this.request(`/sessions/${sessionId}/messages`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
body: JSON.stringify({ content })
|
|
66
|
+
});
|
|
67
|
+
return response;
|
|
68
|
+
}
|
|
69
|
+
async getHistory(sessionId) {
|
|
70
|
+
return this.request(`/sessions/${sessionId}/messages`);
|
|
71
|
+
}
|
|
72
|
+
async getSessions() {
|
|
73
|
+
return this.request("/sessions");
|
|
74
|
+
}
|
|
75
|
+
async getArtifacts() {
|
|
76
|
+
return this.request("/artifacts");
|
|
77
|
+
}
|
|
78
|
+
async getArtifact(id) {
|
|
79
|
+
return this.request(`/artifacts/${id}`);
|
|
80
|
+
}
|
|
81
|
+
async createArtifact(artifact) {
|
|
82
|
+
return this.request("/artifacts", {
|
|
83
|
+
method: "POST",
|
|
84
|
+
body: JSON.stringify(artifact)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async request(endpoint, options = {}) {
|
|
88
|
+
const url = `${this.config.baseUrl}${endpoint}`;
|
|
89
|
+
this.log("Request:", url, options);
|
|
90
|
+
const response = await fetch(url, {
|
|
91
|
+
...options,
|
|
92
|
+
headers: {
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
95
|
+
...options.headers
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const error = await response.json().catch(() => ({}));
|
|
100
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
101
|
+
}
|
|
102
|
+
return response.json();
|
|
103
|
+
}
|
|
104
|
+
log(...args) {
|
|
105
|
+
if (this.config.debug) {
|
|
106
|
+
console.log("[CourseAI]", ...args);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/core/client.ts
|
|
112
|
+
var WidgetClient = class {
|
|
113
|
+
constructor(config) {
|
|
114
|
+
this.state = { status: "idle" };
|
|
115
|
+
this.events = new TypedEventEmitter();
|
|
116
|
+
this.config = config;
|
|
117
|
+
this.api = new WidgetAPI(config);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Initialize the widget and create a chat session
|
|
121
|
+
*/
|
|
122
|
+
async initialize() {
|
|
123
|
+
if (this.state.status !== "idle") {
|
|
124
|
+
throw new Error("Widget already initialized");
|
|
125
|
+
}
|
|
126
|
+
this.setState({ status: "initializing" });
|
|
127
|
+
try {
|
|
128
|
+
const session = await this.api.createSession();
|
|
129
|
+
this.setState({ status: "ready", session });
|
|
130
|
+
this.events.emit("session:created", { session });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const widgetError = {
|
|
133
|
+
code: "INIT_FAILED",
|
|
134
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
135
|
+
details: error
|
|
136
|
+
};
|
|
137
|
+
this.setState({ status: "error", error: widgetError });
|
|
138
|
+
this.events.emit("error", { error: widgetError });
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Send a message to the AI assistant
|
|
144
|
+
*/
|
|
145
|
+
async sendMessage(content) {
|
|
146
|
+
if (this.state.status !== "ready") {
|
|
147
|
+
throw new Error("Widget not ready. Call initialize() first.");
|
|
148
|
+
}
|
|
149
|
+
const userMessage = {
|
|
150
|
+
id: crypto.randomUUID(),
|
|
151
|
+
role: "user",
|
|
152
|
+
content,
|
|
153
|
+
timestamp: Date.now()
|
|
154
|
+
};
|
|
155
|
+
const session = {
|
|
156
|
+
...this.state.session,
|
|
157
|
+
messages: [...this.state.session.messages, userMessage]
|
|
158
|
+
};
|
|
159
|
+
this.setState({ status: "ready", session });
|
|
160
|
+
this.events.emit("message:sent", { message: userMessage });
|
|
161
|
+
this.setState({ status: "loading" });
|
|
162
|
+
try {
|
|
163
|
+
const assistantMessage = await this.api.sendMessage(
|
|
164
|
+
session.id,
|
|
165
|
+
content
|
|
166
|
+
);
|
|
167
|
+
const updatedSession = {
|
|
168
|
+
...session,
|
|
169
|
+
messages: [...session.messages, assistantMessage]
|
|
170
|
+
};
|
|
171
|
+
this.setState({ status: "ready", session: updatedSession });
|
|
172
|
+
this.events.emit("message:received", { message: assistantMessage });
|
|
173
|
+
return assistantMessage;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
const widgetError = {
|
|
176
|
+
code: "SEND_MESSAGE_FAILED",
|
|
177
|
+
message: error instanceof Error ? error.message : "Failed to send message",
|
|
178
|
+
details: error
|
|
179
|
+
};
|
|
180
|
+
this.setState({ status: "ready", session });
|
|
181
|
+
this.events.emit("error", { error: widgetError });
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get current state
|
|
187
|
+
*/
|
|
188
|
+
getState() {
|
|
189
|
+
return this.state;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get the API instance for direct calls
|
|
193
|
+
*/
|
|
194
|
+
getAPI() {
|
|
195
|
+
return this.api;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the widget configuration
|
|
199
|
+
*/
|
|
200
|
+
getConfig() {
|
|
201
|
+
return this.config;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Subscribe to events
|
|
205
|
+
*/
|
|
206
|
+
on(event, handler) {
|
|
207
|
+
return this.events.on(event, handler);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Unsubscribe from events
|
|
211
|
+
*/
|
|
212
|
+
off(event, handler) {
|
|
213
|
+
this.events.off(event, handler);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clean up resources
|
|
217
|
+
*/
|
|
218
|
+
destroy() {
|
|
219
|
+
this.events.clear();
|
|
220
|
+
this.setState({ status: "idle" });
|
|
221
|
+
}
|
|
222
|
+
setState(newState) {
|
|
223
|
+
const previous = this.state;
|
|
224
|
+
this.state = newState;
|
|
225
|
+
this.events.emit("state:change", { previous, current: newState });
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
exports.TypedEventEmitter = TypedEventEmitter;
|
|
230
|
+
exports.WidgetAPI = WidgetAPI;
|
|
231
|
+
exports.WidgetClient = WidgetClient;
|
|
232
|
+
//# sourceMappingURL=index.cjs.map
|
|
233
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/events.ts","../src/core/api.ts","../src/core/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["type EventHandler<T = unknown> = (payload: T) => void;\n\nexport class TypedEventEmitter<TEvents extends Record<string, unknown>> {\n private listeners = new Map<keyof TEvents, Set<EventHandler>>();\n\n on<K extends keyof TEvents>(\n event: K,\n handler: EventHandler<TEvents[K]>\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventHandler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n off<K extends keyof TEvents>(\n event: K,\n handler: EventHandler<TEvents[K]>\n ): void {\n this.listeners.get(event)?.delete(handler as EventHandler);\n }\n\n emit<K extends keyof TEvents>(event: K, payload: TEvents[K]): void {\n this.listeners.get(event)?.forEach((handler) => {\n try {\n handler(payload);\n } catch (error) {\n console.error(`Error in ${String(event)} handler:`, error);\n }\n });\n }\n\n clear(): void {\n this.listeners.clear();\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n\n","import type { WidgetConfig, Message, ChatSession, Artifact } from './types';\n\nexport class WidgetAPI {\n private config: Required<WidgetConfig>;\n\n constructor(config: WidgetConfig) {\n this.config = {\n baseUrl: process.env.WIDGET_API_URL || 'http://localhost:3000',\n userId: '',\n debug: false,\n assistantId: config.apiKey, // Default to apiKey for backwards compatibility\n ...config,\n };\n }\n\n async createSession(): Promise<ChatSession> {\n const response = await this.request<ChatSession>('/sessions', {\n method: 'POST',\n body: JSON.stringify({\n // apiKey IS the assistantId\n assistantId: this.config.apiKey,\n userId: this.config.userId,\n }),\n });\n return response;\n }\n\n async sendMessage(sessionId: string, content: string): Promise<Message> {\n const response = await this.request<Message>(`/sessions/${sessionId}/messages`, {\n method: 'POST',\n body: JSON.stringify({ content }),\n });\n return response;\n }\n\n async getHistory(sessionId: string): Promise<Message[]> {\n return this.request<Message[]>(`/sessions/${sessionId}/messages`);\n }\n\n async getSessions(): Promise<ChatSession[]> {\n return this.request<ChatSession[]>('/sessions');\n }\n\n async getArtifacts(): Promise<Artifact[]> {\n return this.request<Artifact[]>('/artifacts');\n }\n\n async getArtifact(id: string): Promise<Artifact> {\n return this.request<Artifact>(`/artifacts/${id}`);\n }\n\n async createArtifact(artifact: Omit<Artifact, 'id' | 'createdAt' | 'updatedAt'>): Promise<Artifact> {\n return this.request<Artifact>('/artifacts', {\n method: 'POST',\n body: JSON.stringify(artifact),\n });\n }\n\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n \n this.log('Request:', url, options);\n\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.message || `HTTP ${response.status}`);\n }\n\n return response.json();\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[CourseAI]', ...args);\n }\n }\n}\n\n","import { TypedEventEmitter } from './events';\nimport { WidgetAPI } from './api';\nimport type {\n WidgetConfig,\n WidgetState,\n WidgetEvents,\n Message,\n ChatSession,\n} from './types';\n\nexport class WidgetClient {\n private config: WidgetConfig;\n private state: WidgetState = { status: 'idle' };\n private events = new TypedEventEmitter<WidgetEvents>();\n private api: WidgetAPI;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.api = new WidgetAPI(config);\n }\n\n /**\n * Initialize the widget and create a chat session\n */\n async initialize(): Promise<void> {\n if (this.state.status !== 'idle') {\n throw new Error('Widget already initialized');\n }\n\n this.setState({ status: 'initializing' });\n\n try {\n const session = await this.api.createSession();\n this.setState({ status: 'ready', session });\n this.events.emit('session:created', { session });\n } catch (error) {\n const widgetError = {\n code: 'INIT_FAILED',\n message: error instanceof Error ? error.message : 'Unknown error',\n details: error,\n };\n this.setState({ status: 'error', error: widgetError });\n this.events.emit('error', { error: widgetError });\n throw error;\n }\n }\n\n /**\n * Send a message to the AI assistant\n */\n async sendMessage(content: string): Promise<Message> {\n if (this.state.status !== 'ready') {\n throw new Error('Widget not ready. Call initialize() first.');\n }\n\n const userMessage: Message = {\n id: crypto.randomUUID(),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n\n // Optimistically add user message\n const session = {\n ...this.state.session,\n messages: [...this.state.session.messages, userMessage],\n };\n this.setState({ status: 'ready', session });\n this.events.emit('message:sent', { message: userMessage });\n\n // Set loading state\n this.setState({ status: 'loading' });\n\n try {\n const assistantMessage = await this.api.sendMessage(\n session.id,\n content\n );\n\n const updatedSession = {\n ...session,\n messages: [...session.messages, assistantMessage],\n };\n\n this.setState({ status: 'ready', session: updatedSession });\n this.events.emit('message:received', { message: assistantMessage });\n\n return assistantMessage;\n } catch (error) {\n const widgetError = {\n code: 'SEND_MESSAGE_FAILED',\n message: error instanceof Error ? error.message : 'Failed to send message',\n details: error,\n };\n \n // Revert to previous state with user message still included\n this.setState({ status: 'ready', session });\n this.events.emit('error', { error: widgetError });\n throw error;\n }\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return this.state;\n }\n\n /**\n * Get the API instance for direct calls\n */\n getAPI(): WidgetAPI {\n return this.api;\n }\n\n /**\n * Get the widget configuration\n */\n getConfig(): WidgetConfig {\n return this.config;\n }\n\n /**\n * Subscribe to events\n */\n on<K extends keyof WidgetEvents>(\n event: K,\n handler: (payload: WidgetEvents[K]) => void\n ): () => void {\n return this.events.on(event, handler);\n }\n\n /**\n * Unsubscribe from events\n */\n off<K extends keyof WidgetEvents>(\n event: K,\n handler: (payload: WidgetEvents[K]) => void\n ): void {\n this.events.off(event, handler);\n }\n\n /**\n * Clean up resources\n */\n destroy(): void {\n this.events.clear();\n this.setState({ status: 'idle' });\n }\n\n private setState(newState: WidgetState): void {\n const previous = this.state;\n this.state = newState;\n this.events.emit('state:change', { previous, current: newState });\n }\n}\n\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { A as Artifact, f as ArtifactCategory, C as ChatSession, M as Message, a as WidgetAPI, W as WidgetClient, b as WidgetConfig, e as WidgetError, d as WidgetEvents, c as WidgetState } from './client-CExUGn7b.cjs';
|
|
2
|
+
|
|
3
|
+
type EventHandler<T = unknown> = (payload: T) => void;
|
|
4
|
+
declare class TypedEventEmitter<TEvents extends Record<string, unknown>> {
|
|
5
|
+
private listeners;
|
|
6
|
+
on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void;
|
|
7
|
+
off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void;
|
|
8
|
+
emit<K extends keyof TEvents>(event: K, payload: TEvents[K]): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
removeAllListeners(event?: keyof TEvents): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { TypedEventEmitter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { A as Artifact, f as ArtifactCategory, C as ChatSession, M as Message, a as WidgetAPI, W as WidgetClient, b as WidgetConfig, e as WidgetError, d as WidgetEvents, c as WidgetState } from './client-CExUGn7b.js';
|
|
2
|
+
|
|
3
|
+
type EventHandler<T = unknown> = (payload: T) => void;
|
|
4
|
+
declare class TypedEventEmitter<TEvents extends Record<string, unknown>> {
|
|
5
|
+
private listeners;
|
|
6
|
+
on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void;
|
|
7
|
+
off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void;
|
|
8
|
+
emit<K extends keyof TEvents>(event: K, payload: TEvents[K]): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
removeAllListeners(event?: keyof TEvents): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { TypedEventEmitter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// src/core/events.ts
|
|
2
|
+
var TypedEventEmitter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, handler) {
|
|
7
|
+
if (!this.listeners.has(event)) {
|
|
8
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
9
|
+
}
|
|
10
|
+
this.listeners.get(event).add(handler);
|
|
11
|
+
return () => this.off(event, handler);
|
|
12
|
+
}
|
|
13
|
+
off(event, handler) {
|
|
14
|
+
this.listeners.get(event)?.delete(handler);
|
|
15
|
+
}
|
|
16
|
+
emit(event, payload) {
|
|
17
|
+
this.listeners.get(event)?.forEach((handler) => {
|
|
18
|
+
try {
|
|
19
|
+
handler(payload);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(`Error in ${String(event)} handler:`, error);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
clear() {
|
|
26
|
+
this.listeners.clear();
|
|
27
|
+
}
|
|
28
|
+
removeAllListeners(event) {
|
|
29
|
+
if (event) {
|
|
30
|
+
this.listeners.delete(event);
|
|
31
|
+
} else {
|
|
32
|
+
this.listeners.clear();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/core/api.ts
|
|
38
|
+
var WidgetAPI = class {
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.config = {
|
|
41
|
+
baseUrl: "http://localhost:3000",
|
|
42
|
+
userId: "",
|
|
43
|
+
debug: false,
|
|
44
|
+
assistantId: config.apiKey,
|
|
45
|
+
// Default to apiKey for backwards compatibility
|
|
46
|
+
...config
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async createSession() {
|
|
50
|
+
const response = await this.request("/sessions", {
|
|
51
|
+
method: "POST",
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
// apiKey IS the assistantId
|
|
54
|
+
assistantId: this.config.apiKey,
|
|
55
|
+
userId: this.config.userId
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
return response;
|
|
59
|
+
}
|
|
60
|
+
async sendMessage(sessionId, content) {
|
|
61
|
+
const response = await this.request(`/sessions/${sessionId}/messages`, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
body: JSON.stringify({ content })
|
|
64
|
+
});
|
|
65
|
+
return response;
|
|
66
|
+
}
|
|
67
|
+
async getHistory(sessionId) {
|
|
68
|
+
return this.request(`/sessions/${sessionId}/messages`);
|
|
69
|
+
}
|
|
70
|
+
async getSessions() {
|
|
71
|
+
return this.request("/sessions");
|
|
72
|
+
}
|
|
73
|
+
async getArtifacts() {
|
|
74
|
+
return this.request("/artifacts");
|
|
75
|
+
}
|
|
76
|
+
async getArtifact(id) {
|
|
77
|
+
return this.request(`/artifacts/${id}`);
|
|
78
|
+
}
|
|
79
|
+
async createArtifact(artifact) {
|
|
80
|
+
return this.request("/artifacts", {
|
|
81
|
+
method: "POST",
|
|
82
|
+
body: JSON.stringify(artifact)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async request(endpoint, options = {}) {
|
|
86
|
+
const url = `${this.config.baseUrl}${endpoint}`;
|
|
87
|
+
this.log("Request:", url, options);
|
|
88
|
+
const response = await fetch(url, {
|
|
89
|
+
...options,
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/json",
|
|
92
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
93
|
+
...options.headers
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const error = await response.json().catch(() => ({}));
|
|
98
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
99
|
+
}
|
|
100
|
+
return response.json();
|
|
101
|
+
}
|
|
102
|
+
log(...args) {
|
|
103
|
+
if (this.config.debug) {
|
|
104
|
+
console.log("[CourseAI]", ...args);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/core/client.ts
|
|
110
|
+
var WidgetClient = class {
|
|
111
|
+
constructor(config) {
|
|
112
|
+
this.state = { status: "idle" };
|
|
113
|
+
this.events = new TypedEventEmitter();
|
|
114
|
+
this.config = config;
|
|
115
|
+
this.api = new WidgetAPI(config);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Initialize the widget and create a chat session
|
|
119
|
+
*/
|
|
120
|
+
async initialize() {
|
|
121
|
+
if (this.state.status !== "idle") {
|
|
122
|
+
throw new Error("Widget already initialized");
|
|
123
|
+
}
|
|
124
|
+
this.setState({ status: "initializing" });
|
|
125
|
+
try {
|
|
126
|
+
const session = await this.api.createSession();
|
|
127
|
+
this.setState({ status: "ready", session });
|
|
128
|
+
this.events.emit("session:created", { session });
|
|
129
|
+
} catch (error) {
|
|
130
|
+
const widgetError = {
|
|
131
|
+
code: "INIT_FAILED",
|
|
132
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
133
|
+
details: error
|
|
134
|
+
};
|
|
135
|
+
this.setState({ status: "error", error: widgetError });
|
|
136
|
+
this.events.emit("error", { error: widgetError });
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Send a message to the AI assistant
|
|
142
|
+
*/
|
|
143
|
+
async sendMessage(content) {
|
|
144
|
+
if (this.state.status !== "ready") {
|
|
145
|
+
throw new Error("Widget not ready. Call initialize() first.");
|
|
146
|
+
}
|
|
147
|
+
const userMessage = {
|
|
148
|
+
id: crypto.randomUUID(),
|
|
149
|
+
role: "user",
|
|
150
|
+
content,
|
|
151
|
+
timestamp: Date.now()
|
|
152
|
+
};
|
|
153
|
+
const session = {
|
|
154
|
+
...this.state.session,
|
|
155
|
+
messages: [...this.state.session.messages, userMessage]
|
|
156
|
+
};
|
|
157
|
+
this.setState({ status: "ready", session });
|
|
158
|
+
this.events.emit("message:sent", { message: userMessage });
|
|
159
|
+
this.setState({ status: "loading" });
|
|
160
|
+
try {
|
|
161
|
+
const assistantMessage = await this.api.sendMessage(
|
|
162
|
+
session.id,
|
|
163
|
+
content
|
|
164
|
+
);
|
|
165
|
+
const updatedSession = {
|
|
166
|
+
...session,
|
|
167
|
+
messages: [...session.messages, assistantMessage]
|
|
168
|
+
};
|
|
169
|
+
this.setState({ status: "ready", session: updatedSession });
|
|
170
|
+
this.events.emit("message:received", { message: assistantMessage });
|
|
171
|
+
return assistantMessage;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const widgetError = {
|
|
174
|
+
code: "SEND_MESSAGE_FAILED",
|
|
175
|
+
message: error instanceof Error ? error.message : "Failed to send message",
|
|
176
|
+
details: error
|
|
177
|
+
};
|
|
178
|
+
this.setState({ status: "ready", session });
|
|
179
|
+
this.events.emit("error", { error: widgetError });
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get current state
|
|
185
|
+
*/
|
|
186
|
+
getState() {
|
|
187
|
+
return this.state;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the API instance for direct calls
|
|
191
|
+
*/
|
|
192
|
+
getAPI() {
|
|
193
|
+
return this.api;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get the widget configuration
|
|
197
|
+
*/
|
|
198
|
+
getConfig() {
|
|
199
|
+
return this.config;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Subscribe to events
|
|
203
|
+
*/
|
|
204
|
+
on(event, handler) {
|
|
205
|
+
return this.events.on(event, handler);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Unsubscribe from events
|
|
209
|
+
*/
|
|
210
|
+
off(event, handler) {
|
|
211
|
+
this.events.off(event, handler);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Clean up resources
|
|
215
|
+
*/
|
|
216
|
+
destroy() {
|
|
217
|
+
this.events.clear();
|
|
218
|
+
this.setState({ status: "idle" });
|
|
219
|
+
}
|
|
220
|
+
setState(newState) {
|
|
221
|
+
const previous = this.state;
|
|
222
|
+
this.state = newState;
|
|
223
|
+
this.events.emit("state:change", { previous, current: newState });
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
export { TypedEventEmitter, WidgetAPI, WidgetClient };
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
229
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/events.ts","../src/core/api.ts","../src/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["type EventHandler<T = unknown> = (payload: T) => void;\n\nexport class TypedEventEmitter<TEvents extends Record<string, unknown>> {\n private listeners = new Map<keyof TEvents, Set<EventHandler>>();\n\n on<K extends keyof TEvents>(\n event: K,\n handler: EventHandler<TEvents[K]>\n ): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventHandler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n off<K extends keyof TEvents>(\n event: K,\n handler: EventHandler<TEvents[K]>\n ): void {\n this.listeners.get(event)?.delete(handler as EventHandler);\n }\n\n emit<K extends keyof TEvents>(event: K, payload: TEvents[K]): void {\n this.listeners.get(event)?.forEach((handler) => {\n try {\n handler(payload);\n } catch (error) {\n console.error(`Error in ${String(event)} handler:`, error);\n }\n });\n }\n\n clear(): void {\n this.listeners.clear();\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n\n","import type { WidgetConfig, Message, ChatSession, Artifact } from './types';\n\nexport class WidgetAPI {\n private config: Required<WidgetConfig>;\n\n constructor(config: WidgetConfig) {\n this.config = {\n baseUrl: process.env.WIDGET_API_URL || 'http://localhost:3000',\n userId: '',\n debug: false,\n assistantId: config.apiKey, // Default to apiKey for backwards compatibility\n ...config,\n };\n }\n\n async createSession(): Promise<ChatSession> {\n const response = await this.request<ChatSession>('/sessions', {\n method: 'POST',\n body: JSON.stringify({\n // apiKey IS the assistantId\n assistantId: this.config.apiKey,\n userId: this.config.userId,\n }),\n });\n return response;\n }\n\n async sendMessage(sessionId: string, content: string): Promise<Message> {\n const response = await this.request<Message>(`/sessions/${sessionId}/messages`, {\n method: 'POST',\n body: JSON.stringify({ content }),\n });\n return response;\n }\n\n async getHistory(sessionId: string): Promise<Message[]> {\n return this.request<Message[]>(`/sessions/${sessionId}/messages`);\n }\n\n async getSessions(): Promise<ChatSession[]> {\n return this.request<ChatSession[]>('/sessions');\n }\n\n async getArtifacts(): Promise<Artifact[]> {\n return this.request<Artifact[]>('/artifacts');\n }\n\n async getArtifact(id: string): Promise<Artifact> {\n return this.request<Artifact>(`/artifacts/${id}`);\n }\n\n async createArtifact(artifact: Omit<Artifact, 'id' | 'createdAt' | 'updatedAt'>): Promise<Artifact> {\n return this.request<Artifact>('/artifacts', {\n method: 'POST',\n body: JSON.stringify(artifact),\n });\n }\n\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n \n this.log('Request:', url, options);\n\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(error.message || `HTTP ${response.status}`);\n }\n\n return response.json();\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[CourseAI]', ...args);\n }\n }\n}\n\n","import { TypedEventEmitter } from './events';\nimport { WidgetAPI } from './api';\nimport type {\n WidgetConfig,\n WidgetState,\n WidgetEvents,\n Message,\n ChatSession,\n} from './types';\n\nexport class WidgetClient {\n private config: WidgetConfig;\n private state: WidgetState = { status: 'idle' };\n private events = new TypedEventEmitter<WidgetEvents>();\n private api: WidgetAPI;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.api = new WidgetAPI(config);\n }\n\n /**\n * Initialize the widget and create a chat session\n */\n async initialize(): Promise<void> {\n if (this.state.status !== 'idle') {\n throw new Error('Widget already initialized');\n }\n\n this.setState({ status: 'initializing' });\n\n try {\n const session = await this.api.createSession();\n this.setState({ status: 'ready', session });\n this.events.emit('session:created', { session });\n } catch (error) {\n const widgetError = {\n code: 'INIT_FAILED',\n message: error instanceof Error ? error.message : 'Unknown error',\n details: error,\n };\n this.setState({ status: 'error', error: widgetError });\n this.events.emit('error', { error: widgetError });\n throw error;\n }\n }\n\n /**\n * Send a message to the AI assistant\n */\n async sendMessage(content: string): Promise<Message> {\n if (this.state.status !== 'ready') {\n throw new Error('Widget not ready. Call initialize() first.');\n }\n\n const userMessage: Message = {\n id: crypto.randomUUID(),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n\n // Optimistically add user message\n const session = {\n ...this.state.session,\n messages: [...this.state.session.messages, userMessage],\n };\n this.setState({ status: 'ready', session });\n this.events.emit('message:sent', { message: userMessage });\n\n // Set loading state\n this.setState({ status: 'loading' });\n\n try {\n const assistantMessage = await this.api.sendMessage(\n session.id,\n content\n );\n\n const updatedSession = {\n ...session,\n messages: [...session.messages, assistantMessage],\n };\n\n this.setState({ status: 'ready', session: updatedSession });\n this.events.emit('message:received', { message: assistantMessage });\n\n return assistantMessage;\n } catch (error) {\n const widgetError = {\n code: 'SEND_MESSAGE_FAILED',\n message: error instanceof Error ? error.message : 'Failed to send message',\n details: error,\n };\n \n // Revert to previous state with user message still included\n this.setState({ status: 'ready', session });\n this.events.emit('error', { error: widgetError });\n throw error;\n }\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return this.state;\n }\n\n /**\n * Get the API instance for direct calls\n */\n getAPI(): WidgetAPI {\n return this.api;\n }\n\n /**\n * Get the widget configuration\n */\n getConfig(): WidgetConfig {\n return this.config;\n }\n\n /**\n * Subscribe to events\n */\n on<K extends keyof WidgetEvents>(\n event: K,\n handler: (payload: WidgetEvents[K]) => void\n ): () => void {\n return this.events.on(event, handler);\n }\n\n /**\n * Unsubscribe from events\n */\n off<K extends keyof WidgetEvents>(\n event: K,\n handler: (payload: WidgetEvents[K]) => void\n ): void {\n this.events.off(event, handler);\n }\n\n /**\n * Clean up resources\n */\n destroy(): void {\n this.events.clear();\n this.setState({ status: 'idle' });\n }\n\n private setState(newState: WidgetState): void {\n const previous = this.state;\n this.state = newState;\n this.events.emit('state:change', { previous, current: newState });\n }\n}\n\n"]}
|