@maxaiagent/widget-sdk 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/README.md +270 -0
- package/dist/index.d.mts +142 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.global.js +29 -0
- package/dist/index.mjs +29 -0
- package/package.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# @maxai/widget-sdk
|
|
2
|
+
|
|
3
|
+
SDK do osadzania widgetu czatu MaxAI na dowolnej stronie internetowej.
|
|
4
|
+
|
|
5
|
+
## Instalacja
|
|
6
|
+
|
|
7
|
+
### NPM (React, Vue, Next.js, itp.)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @maxai/widget-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { MaxAI } from '@maxai/widget-sdk'
|
|
15
|
+
|
|
16
|
+
const widget = MaxAI.init({ key: 'TWOJ_KLUCZ' })
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### CDN (zwykły HTML)
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script src="https://maxaiagent.app/sdk.js" data-key="TWOJ_KLUCZ"></script>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Widget automatycznie się zainicjalizuje. Aby korzystać z API SDK:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<script src="https://maxaiagent.app/sdk.js" data-key="TWOJ_KLUCZ"></script>
|
|
29
|
+
<script>
|
|
30
|
+
// MaxAI jest dostępny globalnie
|
|
31
|
+
MaxAI.setPageContext({ pageType: 'product', visibleData: { name: 'Buty Nike', price: 549 } })
|
|
32
|
+
</script>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
### `MaxAI.init(options)`
|
|
40
|
+
|
|
41
|
+
Inicjalizuje widget. Zwraca `WidgetInstance`.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const widget = MaxAI.init({
|
|
45
|
+
key: 'TWOJ_KLUCZ', // Wymagane — klucz z panelu MaxAI
|
|
46
|
+
position: 'bottom-right', // 'bottom-right' | 'bottom-left'
|
|
47
|
+
baseUrl: 'https://maxaiagent.app', // Opcjonalne — override URL serwera
|
|
48
|
+
nonce: 'abc123', // Opcjonalne — CSP nonce dla stylów
|
|
49
|
+
lazy: false, // Opcjonalne — lazy load iframe
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `widget.setPageContext(context)`
|
|
54
|
+
|
|
55
|
+
Wysyła kontekst strony do agenta AI. Agent automatycznie zbiera tytuł, URL, meta tagi i JSON-LD. Użyj tej metody, aby dodać **dodatkowe** dane.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
widget.setPageContext({
|
|
59
|
+
pageType: 'product',
|
|
60
|
+
visibleData: {
|
|
61
|
+
name: 'Nike Air Max 90',
|
|
62
|
+
price: 549,
|
|
63
|
+
currency: 'PLN',
|
|
64
|
+
sizes: [40, 41, 42, 43, 44, 45, 46],
|
|
65
|
+
},
|
|
66
|
+
customContext: {
|
|
67
|
+
user_type: 'premium',
|
|
68
|
+
cart_count: '3',
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `widget.registerTool(definition)`
|
|
74
|
+
|
|
75
|
+
Rejestruje narzędzie po stronie klienta. Agent AI może je wywoływać w trakcie rozmowy. Zwraca funkcję do wyrejestrowania.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
const unregister = widget.registerTool({
|
|
79
|
+
name: 'add_to_cart',
|
|
80
|
+
description: 'Dodaje produkt do koszyka użytkownika',
|
|
81
|
+
schema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
product_id: { type: 'string', description: 'ID produktu' },
|
|
85
|
+
quantity: { type: 'number', description: 'Ilość', default: 1 },
|
|
86
|
+
size: { type: 'string', description: 'Rozmiar (np. "42")' },
|
|
87
|
+
},
|
|
88
|
+
required: ['product_id'],
|
|
89
|
+
},
|
|
90
|
+
requiresConfirmation: true, // Pokaż dialog potwierdzenia
|
|
91
|
+
handler: async (args) => {
|
|
92
|
+
// Twoja logika biznesowa
|
|
93
|
+
const result = await myAPI.addToCart(args.product_id, args.quantity, args.size)
|
|
94
|
+
return { success: true, cart_count: result.totalItems }
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// Później:
|
|
99
|
+
unregister()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `widget.on(event, callback)`
|
|
103
|
+
|
|
104
|
+
Nasłuchuje na zdarzenia widgetu. Zwraca funkcję do odsubskrybowania.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Nowa wiadomość od agenta
|
|
108
|
+
widget.on('message', (msg) => {
|
|
109
|
+
console.log(`${msg.role}: ${msg.content}`)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// Agent wywołuje narzędzie
|
|
113
|
+
widget.on('tool:call', (call) => {
|
|
114
|
+
console.log(`Tool: ${call.name}`, call.args)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Widget otwarty/zamknięty
|
|
118
|
+
widget.on('open', () => console.log('Widget otwarty'))
|
|
119
|
+
widget.on('close', () => console.log('Widget zamknięty'))
|
|
120
|
+
|
|
121
|
+
// Widget gotowy (iframe załadowany)
|
|
122
|
+
widget.on('ready', () => console.log('Widget gotowy'))
|
|
123
|
+
|
|
124
|
+
// Błąd
|
|
125
|
+
widget.on('error', (err) => console.error('Błąd:', err.message))
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `widget.open()` / `widget.close()`
|
|
129
|
+
|
|
130
|
+
Steruj widgetem programowo.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Otwórz po 5 sekundach
|
|
134
|
+
setTimeout(() => widget.open(), 5000)
|
|
135
|
+
|
|
136
|
+
// Zamknij po wysłaniu formularza
|
|
137
|
+
form.onsubmit = () => widget.close()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### `widget.destroy()`
|
|
141
|
+
|
|
142
|
+
Usuwa widget ze strony i czyści wszystkie listenery.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
widget.destroy()
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Atrybuty `data-context-*`
|
|
151
|
+
|
|
152
|
+
Dodatkowy kontekst można przekazać bezpośrednio w tagu `<script>`:
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<script
|
|
156
|
+
src="https://maxaiagent.app/sdk.js"
|
|
157
|
+
data-key="TWOJ_KLUCZ"
|
|
158
|
+
data-context-page="product"
|
|
159
|
+
data-context-user-type="premium"
|
|
160
|
+
data-context-cart-items="3"
|
|
161
|
+
></script>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Agent otrzyma te dane jako `customContext: { page: 'product', user_type: 'premium', cart_items: '3' }`.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Przykłady
|
|
169
|
+
|
|
170
|
+
### E-commerce — strona produktu
|
|
171
|
+
|
|
172
|
+
```html
|
|
173
|
+
<script src="https://maxaiagent.app/sdk.js" data-key="KLUCZ"></script>
|
|
174
|
+
<script>
|
|
175
|
+
MaxAI.setPageContext({
|
|
176
|
+
pageType: 'product',
|
|
177
|
+
visibleData: {
|
|
178
|
+
name: document.querySelector('h1').textContent,
|
|
179
|
+
price: document.querySelector('.price').textContent,
|
|
180
|
+
inStock: document.querySelector('.stock')?.textContent !== 'Brak',
|
|
181
|
+
},
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
MaxAI.registerTool({
|
|
185
|
+
name: 'add_to_cart',
|
|
186
|
+
description: 'Dodaje aktualny produkt do koszyka',
|
|
187
|
+
schema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
size: { type: 'string', description: 'Wybrany rozmiar' },
|
|
191
|
+
quantity: { type: 'number', default: 1 },
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
requiresConfirmation: true,
|
|
195
|
+
handler: async (args) => {
|
|
196
|
+
document.querySelector('.size-select').value = args.size
|
|
197
|
+
document.querySelector('.add-to-cart-btn').click()
|
|
198
|
+
return { success: true, message: 'Dodano do koszyka' }
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
</script>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### SPA (React/Next.js)
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
import { useEffect } from 'react'
|
|
208
|
+
import { MaxAI } from '@maxai/widget-sdk'
|
|
209
|
+
|
|
210
|
+
export default function Layout({ children }) {
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
const widget = MaxAI.init({ key: 'KLUCZ' })
|
|
213
|
+
|
|
214
|
+
return () => widget.destroy()
|
|
215
|
+
}, [])
|
|
216
|
+
|
|
217
|
+
return <>{children}</>
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
// Na stronie produktu
|
|
223
|
+
import { MaxAI } from '@maxai/widget-sdk'
|
|
224
|
+
|
|
225
|
+
export default function ProductPage({ product }) {
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
MaxAI.setPageContext({
|
|
228
|
+
pageType: 'product',
|
|
229
|
+
visibleData: { name: product.name, price: product.price },
|
|
230
|
+
})
|
|
231
|
+
}, [product])
|
|
232
|
+
|
|
233
|
+
return <div>...</div>
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Typy TypeScript
|
|
240
|
+
|
|
241
|
+
Pełne typy są dostępne po instalacji z npm:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import type {
|
|
245
|
+
MaxAIInitOptions,
|
|
246
|
+
PageContext,
|
|
247
|
+
ToolDefinition,
|
|
248
|
+
WidgetInstance,
|
|
249
|
+
WidgetEvent,
|
|
250
|
+
ChatMessage,
|
|
251
|
+
ToolCallEvent,
|
|
252
|
+
} from '@maxai/widget-sdk'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Funkcje automatyczne
|
|
258
|
+
|
|
259
|
+
Po włączeniu w panelu MaxAI (zakładka "Inteligencja"):
|
|
260
|
+
|
|
261
|
+
| Funkcja | Opis | Wymaga kodu? |
|
|
262
|
+
|---|---|---|
|
|
263
|
+
| **Kontekst strony** | Agent widzi tytuł, URL, meta, JSON-LD, treść `<main>` | Nie |
|
|
264
|
+
| **Point-and-Ask** | Użytkownik wskazuje element na stronie | Nie |
|
|
265
|
+
| **Zgłaszanie problemów** | Przycisk bug report z logami konsoli | Nie |
|
|
266
|
+
| **GDPR** | Baner zgody przed zbieraniem danych | Nie |
|
|
267
|
+
| **Auto-adaptive theme** | Widget dopasowuje kolory do strony | Nie |
|
|
268
|
+
| **Glassmorphism** | Półprzezroczysty efekt szkła | Nie |
|
|
269
|
+
| **Narzędzia klienta** | `registerTool()` — agent wywołuje funkcje | **Tak** |
|
|
270
|
+
| **Explicit context** | `setPageContext()` — dodatkowe dane | **Tak** |
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
interface MaxAIInitOptions {
|
|
2
|
+
/** Widget key from MaxAI dashboard */
|
|
3
|
+
key: string;
|
|
4
|
+
/** Widget position on page */
|
|
5
|
+
position?: "bottom-right" | "bottom-left";
|
|
6
|
+
/** Override base URL (defaults to script origin or maxaiagent.app) */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/** CSP nonce for injected styles */
|
|
9
|
+
nonce?: string;
|
|
10
|
+
/** Lazy load — only load iframe on first open */
|
|
11
|
+
lazy?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface PageContext {
|
|
14
|
+
url?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
pageType?: string;
|
|
18
|
+
visibleData?: Record<string, unknown>;
|
|
19
|
+
customContext?: Record<string, string>;
|
|
20
|
+
ogTitle?: string;
|
|
21
|
+
ogDescription?: string;
|
|
22
|
+
jsonLd?: Record<string, unknown>[];
|
|
23
|
+
mainContent?: string;
|
|
24
|
+
lang?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ToolDefinition {
|
|
27
|
+
/** Unique tool name (alphanumeric + underscore) */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Human-readable description for the AI agent */
|
|
30
|
+
description: string;
|
|
31
|
+
/** JSON Schema for tool arguments */
|
|
32
|
+
schema: Record<string, unknown>;
|
|
33
|
+
/** Function that executes when the agent calls this tool */
|
|
34
|
+
handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
35
|
+
/** If true, widget shows confirmation dialog before executing */
|
|
36
|
+
requiresConfirmation?: boolean;
|
|
37
|
+
/** Tool category for grouping */
|
|
38
|
+
category?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ChatMessage {
|
|
41
|
+
role: "user" | "assistant";
|
|
42
|
+
content: string;
|
|
43
|
+
id: string;
|
|
44
|
+
}
|
|
45
|
+
interface ToolCallEvent {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
args: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
interface ToolResultEvent {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
ok: boolean;
|
|
54
|
+
data?: unknown;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
interface ErrorEvent {
|
|
58
|
+
message: string;
|
|
59
|
+
code?: string;
|
|
60
|
+
}
|
|
61
|
+
type WidgetEventMap = {
|
|
62
|
+
message: ChatMessage;
|
|
63
|
+
"tool:call": ToolCallEvent;
|
|
64
|
+
"tool:result": ToolResultEvent;
|
|
65
|
+
open: void;
|
|
66
|
+
close: void;
|
|
67
|
+
ready: void;
|
|
68
|
+
error: ErrorEvent;
|
|
69
|
+
};
|
|
70
|
+
type WidgetEvent = keyof WidgetEventMap;
|
|
71
|
+
interface WidgetInstance {
|
|
72
|
+
/** Send explicit page context to the widget */
|
|
73
|
+
setPageContext(ctx: Partial<PageContext>): void;
|
|
74
|
+
/** Register a client-side tool. Returns unregister function. */
|
|
75
|
+
registerTool(def: ToolDefinition): () => void;
|
|
76
|
+
/** Unregister a tool by name */
|
|
77
|
+
unregisterTool(name: string): void;
|
|
78
|
+
/** Subscribe to widget events. Returns unsubscribe function. */
|
|
79
|
+
on<E extends WidgetEvent>(event: E, callback: WidgetEventMap[E] extends void ? () => void : (data: WidgetEventMap[E]) => void): () => void;
|
|
80
|
+
/** Unsubscribe from widget events */
|
|
81
|
+
off<E extends WidgetEvent>(event: E, callback: WidgetEventMap[E] extends void ? () => void : (data: WidgetEventMap[E]) => void): void;
|
|
82
|
+
/** Open the chat panel */
|
|
83
|
+
open(): void;
|
|
84
|
+
/** Close the chat panel */
|
|
85
|
+
close(): void;
|
|
86
|
+
/** Remove widget from page and clean up all listeners */
|
|
87
|
+
destroy(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* MaxAI Widget SDK
|
|
92
|
+
*
|
|
93
|
+
* Usage (npm):
|
|
94
|
+
* import { MaxAI } from '@maxai/widget-sdk'
|
|
95
|
+
* const widget = MaxAI.init({ key: 'YOUR_KEY' })
|
|
96
|
+
* widget.registerTool({ name: 'add_to_cart', ... })
|
|
97
|
+
*
|
|
98
|
+
* Usage (CDN):
|
|
99
|
+
* <script src="https://maxaiagent.app/sdk.js" data-key="YOUR_KEY"></script>
|
|
100
|
+
* <script>
|
|
101
|
+
* MaxAI.registerTool({ name: 'add_to_cart', ... })
|
|
102
|
+
* </script>
|
|
103
|
+
*/
|
|
104
|
+
declare const MaxAI: {
|
|
105
|
+
/**
|
|
106
|
+
* Initialize the widget. Returns a WidgetInstance for full control.
|
|
107
|
+
*/
|
|
108
|
+
init(opts: MaxAIInitOptions): WidgetInstance;
|
|
109
|
+
/**
|
|
110
|
+
* Set page context (shorthand — delegates to active instance).
|
|
111
|
+
*/
|
|
112
|
+
setPageContext(ctx: Partial<PageContext>): void;
|
|
113
|
+
/**
|
|
114
|
+
* Register a client-side tool (shorthand — delegates to active instance).
|
|
115
|
+
* Returns an unregister function.
|
|
116
|
+
*/
|
|
117
|
+
registerTool(def: ToolDefinition): () => void;
|
|
118
|
+
/**
|
|
119
|
+
* Unregister a tool by name.
|
|
120
|
+
*/
|
|
121
|
+
unregisterTool(name: string): void;
|
|
122
|
+
/**
|
|
123
|
+
* Subscribe to events.
|
|
124
|
+
*/
|
|
125
|
+
on(event: WidgetEvent, callback: (...args: unknown[]) => void): () => void;
|
|
126
|
+
/**
|
|
127
|
+
* Open the chat panel.
|
|
128
|
+
*/
|
|
129
|
+
open(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Close the chat panel.
|
|
132
|
+
*/
|
|
133
|
+
close(): void;
|
|
134
|
+
/**
|
|
135
|
+
* Destroy widget and clean up.
|
|
136
|
+
*/
|
|
137
|
+
destroy(): void;
|
|
138
|
+
/** Internal flag */
|
|
139
|
+
_initialized: boolean;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export { type ChatMessage, type ErrorEvent, MaxAI, type MaxAIInitOptions, type PageContext, type ToolCallEvent, type ToolDefinition, type ToolResultEvent, type WidgetEvent, type WidgetEventMap, type WidgetInstance };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
interface MaxAIInitOptions {
|
|
2
|
+
/** Widget key from MaxAI dashboard */
|
|
3
|
+
key: string;
|
|
4
|
+
/** Widget position on page */
|
|
5
|
+
position?: "bottom-right" | "bottom-left";
|
|
6
|
+
/** Override base URL (defaults to script origin or maxaiagent.app) */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/** CSP nonce for injected styles */
|
|
9
|
+
nonce?: string;
|
|
10
|
+
/** Lazy load — only load iframe on first open */
|
|
11
|
+
lazy?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface PageContext {
|
|
14
|
+
url?: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
pageType?: string;
|
|
18
|
+
visibleData?: Record<string, unknown>;
|
|
19
|
+
customContext?: Record<string, string>;
|
|
20
|
+
ogTitle?: string;
|
|
21
|
+
ogDescription?: string;
|
|
22
|
+
jsonLd?: Record<string, unknown>[];
|
|
23
|
+
mainContent?: string;
|
|
24
|
+
lang?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ToolDefinition {
|
|
27
|
+
/** Unique tool name (alphanumeric + underscore) */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Human-readable description for the AI agent */
|
|
30
|
+
description: string;
|
|
31
|
+
/** JSON Schema for tool arguments */
|
|
32
|
+
schema: Record<string, unknown>;
|
|
33
|
+
/** Function that executes when the agent calls this tool */
|
|
34
|
+
handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
35
|
+
/** If true, widget shows confirmation dialog before executing */
|
|
36
|
+
requiresConfirmation?: boolean;
|
|
37
|
+
/** Tool category for grouping */
|
|
38
|
+
category?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ChatMessage {
|
|
41
|
+
role: "user" | "assistant";
|
|
42
|
+
content: string;
|
|
43
|
+
id: string;
|
|
44
|
+
}
|
|
45
|
+
interface ToolCallEvent {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
args: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
interface ToolResultEvent {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
ok: boolean;
|
|
54
|
+
data?: unknown;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
interface ErrorEvent {
|
|
58
|
+
message: string;
|
|
59
|
+
code?: string;
|
|
60
|
+
}
|
|
61
|
+
type WidgetEventMap = {
|
|
62
|
+
message: ChatMessage;
|
|
63
|
+
"tool:call": ToolCallEvent;
|
|
64
|
+
"tool:result": ToolResultEvent;
|
|
65
|
+
open: void;
|
|
66
|
+
close: void;
|
|
67
|
+
ready: void;
|
|
68
|
+
error: ErrorEvent;
|
|
69
|
+
};
|
|
70
|
+
type WidgetEvent = keyof WidgetEventMap;
|
|
71
|
+
interface WidgetInstance {
|
|
72
|
+
/** Send explicit page context to the widget */
|
|
73
|
+
setPageContext(ctx: Partial<PageContext>): void;
|
|
74
|
+
/** Register a client-side tool. Returns unregister function. */
|
|
75
|
+
registerTool(def: ToolDefinition): () => void;
|
|
76
|
+
/** Unregister a tool by name */
|
|
77
|
+
unregisterTool(name: string): void;
|
|
78
|
+
/** Subscribe to widget events. Returns unsubscribe function. */
|
|
79
|
+
on<E extends WidgetEvent>(event: E, callback: WidgetEventMap[E] extends void ? () => void : (data: WidgetEventMap[E]) => void): () => void;
|
|
80
|
+
/** Unsubscribe from widget events */
|
|
81
|
+
off<E extends WidgetEvent>(event: E, callback: WidgetEventMap[E] extends void ? () => void : (data: WidgetEventMap[E]) => void): void;
|
|
82
|
+
/** Open the chat panel */
|
|
83
|
+
open(): void;
|
|
84
|
+
/** Close the chat panel */
|
|
85
|
+
close(): void;
|
|
86
|
+
/** Remove widget from page and clean up all listeners */
|
|
87
|
+
destroy(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* MaxAI Widget SDK
|
|
92
|
+
*
|
|
93
|
+
* Usage (npm):
|
|
94
|
+
* import { MaxAI } from '@maxai/widget-sdk'
|
|
95
|
+
* const widget = MaxAI.init({ key: 'YOUR_KEY' })
|
|
96
|
+
* widget.registerTool({ name: 'add_to_cart', ... })
|
|
97
|
+
*
|
|
98
|
+
* Usage (CDN):
|
|
99
|
+
* <script src="https://maxaiagent.app/sdk.js" data-key="YOUR_KEY"></script>
|
|
100
|
+
* <script>
|
|
101
|
+
* MaxAI.registerTool({ name: 'add_to_cart', ... })
|
|
102
|
+
* </script>
|
|
103
|
+
*/
|
|
104
|
+
declare const MaxAI: {
|
|
105
|
+
/**
|
|
106
|
+
* Initialize the widget. Returns a WidgetInstance for full control.
|
|
107
|
+
*/
|
|
108
|
+
init(opts: MaxAIInitOptions): WidgetInstance;
|
|
109
|
+
/**
|
|
110
|
+
* Set page context (shorthand — delegates to active instance).
|
|
111
|
+
*/
|
|
112
|
+
setPageContext(ctx: Partial<PageContext>): void;
|
|
113
|
+
/**
|
|
114
|
+
* Register a client-side tool (shorthand — delegates to active instance).
|
|
115
|
+
* Returns an unregister function.
|
|
116
|
+
*/
|
|
117
|
+
registerTool(def: ToolDefinition): () => void;
|
|
118
|
+
/**
|
|
119
|
+
* Unregister a tool by name.
|
|
120
|
+
*/
|
|
121
|
+
unregisterTool(name: string): void;
|
|
122
|
+
/**
|
|
123
|
+
* Subscribe to events.
|
|
124
|
+
*/
|
|
125
|
+
on(event: WidgetEvent, callback: (...args: unknown[]) => void): () => void;
|
|
126
|
+
/**
|
|
127
|
+
* Open the chat panel.
|
|
128
|
+
*/
|
|
129
|
+
open(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Close the chat panel.
|
|
132
|
+
*/
|
|
133
|
+
close(): void;
|
|
134
|
+
/**
|
|
135
|
+
* Destroy widget and clean up.
|
|
136
|
+
*/
|
|
137
|
+
destroy(): void;
|
|
138
|
+
/** Internal flag */
|
|
139
|
+
_initialized: boolean;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export { type ChatMessage, type ErrorEvent, MaxAI, type MaxAIInitOptions, type PageContext, type ToolCallEvent, type ToolDefinition, type ToolResultEvent, type WidgetEvent, type WidgetEventMap, type WidgetInstance };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* @maxai/widget-sdk v1.0.0 | MIT License | maxaiagent.app */
|
|
2
|
+
"use strict";var MaxAISDK=(()=>{var u=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames,R=Object.getOwnPropertySymbols;var G=Object.prototype.hasOwnProperty,pt=Object.prototype.propertyIsEnumerable;var k=(n,t,e)=>t in n?u(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e,h=(n,t)=>{for(var e in t||(t={}))G.call(t,e)&&k(n,e,t[e]);if(R)for(var e of R(t))pt.call(t,e)&&k(n,e,t[e]);return n};var ct=(n,t)=>{for(var e in t)u(n,e,{get:t[e],enumerable:!0})},ht=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of dt(t))!G.call(n,s)&&s!==e&&u(n,s,{get:()=>t[s],enumerable:!(i=lt(t,s))||i.enumerable});return n};var ut=n=>ht(u({},"__esModule",{value:!0}),n);var bt={};ct(bt,{MaxAI:()=>H});var g=class{constructor(t){this.iframe=null;this.ready=!1;this.queue=[];this.handlers=new Map;this.boundListener=null;this.baseUrl=t}attach(t){this.iframe=t,this.boundListener=e=>this.onMessage(e),window.addEventListener("message",this.boundListener)}markReady(){this.ready=!0;for(let t of this.queue)this.sendRaw(t);this.queue=[]}send(t,e){let i=h({type:t},e);this.ready&&this.iframe?this.sendRaw(i):this.queue.push(i)}listen(t,e){this.handlers.set(t,e)}destroy(){this.boundListener&&(window.removeEventListener("message",this.boundListener),this.boundListener=null),this.handlers.clear(),this.queue=[],this.iframe=null,this.ready=!1}sendRaw(t){var e,i;try{(i=(e=this.iframe)==null?void 0:e.contentWindow)==null||i.postMessage(t,this.baseUrl||"*")}catch(s){}}onMessage(t){if(!t.data||!t.data.type||this.iframe&&t.source!==this.iframe.contentWindow)return;let e=this.handlers.get(t.data.type);e&&e(t.data)}};var m=class{constructor(){this.listeners=new Map}on(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>this.off(t,e)}off(t,e){var i;(i=this.listeners.get(t))==null||i.delete(e)}emit(t,...e){var i;(i=this.listeners.get(t))==null||i.forEach(s=>{try{s(...e)}catch(o){console.error("[MaxAI SDK]",o)}})}removeAll(){this.listeners.clear()}};var I="max-widget:page-context",P="max-widget:register-tools",D="max-widget:unregister-tool",f="max-widget:tool-result",U="max-widget:point-ask-result",v="max-widget:point-ask-cancel",x="max-widget:host-styles",N="max-widget:debug-snapshot",X="max-widget:config-features";var q="max-widget:expand",z="max-widget:hide",W="max-widget:request-page-context",K="max-widget:start-point-ask",j="max-widget:stop-point-ask",F="max-widget:execute-tool",B="max-widget:request-debug-snapshot",Y="max-widget:request-host-styles",$="max-widget:gdpr-consent",Z="max-widget:navigate",Q="max-widget:message",V="max-widget:error";var y=class{constructor(t){this.tools=new Map;this.transport=t}register(t){return!t.name||!/^[a-zA-Z0-9_]+$/.test(t.name)?(console.error("[MaxAI SDK] Invalid tool name:",t.name),()=>{}):(this.tools.set(t.name,h({},t)),this.sendList(),()=>this.unregister(t.name))}unregister(t){this.tools.has(t)&&(this.tools.delete(t),this.transport.send(D,{name:t}),this.sendList())}async execute(t,e,i){let s=this.tools.get(e);if(!(s!=null&&s.handler)){this.transport.send(f,{toolCallId:t,ok:!1,error:`Tool "${e}" not found or has no handler`});return}try{let o=await s.handler(i);this.transport.send(f,{toolCallId:t,ok:!0,data:o}),window.dispatchEvent(new CustomEvent("MaxAI:DataMutated",{detail:{toolName:e,args:i}}))}catch(o){this.transport.send(f,{toolCallId:t,ok:!1,error:o instanceof Error?o.message:"Tool execution failed"})}}sendList(){let t=Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description,schema:e.schema,requiresConfirmation:e.requiresConfirmation||!1,category:e.category||""}));this.transport.send(P,{tools:t})}hasTools(){return this.tools.size>0}destroy(){this.tools.clear()}};function w(n,t){return n.length>t?n.slice(0,t)+"\u2026":n}var mt=[/Bearer\s+[A-Za-z0-9\-._~+/]+=*/g,/token=[A-Za-z0-9\-._~+/]+=*/g,/password["'\s:=]+["']?[^\s"',}]*/gi,/api[_-]?key["'\s:=]+["']?[A-Za-z0-9\-._~+/]*/gi,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g];function ft(n){let t=JSON.stringify(n);for(let e of mt)t=t.replace(e,"[REDACTED]");try{return JSON.parse(t)}catch(e){return n}}var E=class{constructor(){this.consoleLogs=[];this.networkLog=[];this.errors=[];this.origConsole={};this.origFetch=null;this.origXHROpen=null;this.origXHRSend=null;this.errorHandler=null;this.rejectionHandler=null;this.initialized=!1}init(){if(this.initialized)return;this.initialized=!0;for(let e of["log","warn","error"])this.origConsole[e]=console[e].bind(console),console[e]=(...i)=>{this.origConsole[e](...i);try{let s=i.map(o=>{try{return typeof o=="string"?o:JSON.stringify(o)}catch(a){return String(o)}}).join(" ");this.consoleLogs.push({level:e,message:w(s,500),timestamp:Date.now()}),this.consoleLogs.length>50&&this.consoleLogs.shift()}catch(s){}};this.errorHandler=e=>{this.errors.push({message:e.message||"",source:e.filename||"",line:e.lineno||0,col:e.colno||0,timestamp:Date.now()}),this.errors.length>50&&this.errors.shift()},window.addEventListener("error",this.errorHandler),this.rejectionHandler=e=>{this.errors.push({message:"Unhandled rejection: "+(e.reason?String(e.reason):"unknown"),timestamp:Date.now()}),this.errors.length>50&&this.errors.shift()},window.addEventListener("unhandledrejection",this.rejectionHandler),this.origFetch=window.fetch,window.fetch=(...e)=>{let i=e[0],o=((e[1]||{}).method||"GET").toUpperCase(),a=Date.now();return this.origFetch(...e).then(r=>(this.networkLog.push({method:o,url:typeof i=="string"?w(i,200):"(Request)",status:r.status,duration:Date.now()-a,timestamp:a}),this.networkLog.length>30&&this.networkLog.shift(),r)).catch(r=>{throw this.networkLog.push({method:o,url:typeof i=="string"?w(i,200):"(Request)",status:0,error:r.message||"Network error",duration:Date.now()-a,timestamp:a}),this.networkLog.length>30&&this.networkLog.shift(),r})},this.origXHROpen=XMLHttpRequest.prototype.open,this.origXHRSend=XMLHttpRequest.prototype.send;let t=this;XMLHttpRequest.prototype.open=function(e,i){return this._m=e,this._u=String(i),this._t=Date.now(),t.origXHROpen.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let e=this;return e.addEventListener("loadend",()=>{t.networkLog.push({method:(e._m||"GET").toUpperCase(),url:w(e._u||"",200),status:e.status,duration:Date.now()-(e._t||Date.now()),timestamp:e._t||Date.now()}),t.networkLog.length>30&&t.networkLog.shift()}),t.origXHRSend.apply(this,arguments)}}getSnapshot(){return ft({consoleLogs:this.consoleLogs.slice(),networkLog:this.networkLog.slice(),errors:this.errors.slice(),pageUrl:window.location.href,timestamp:Date.now()})}destroy(){if(this.initialized){for(let t of Object.keys(this.origConsole))console[t]=this.origConsole[t];this.origFetch&&(window.fetch=this.origFetch),this.origXHROpen&&(XMLHttpRequest.prototype.open=this.origXHROpen),this.origXHRSend&&(XMLHttpRequest.prototype.send=this.origXHRSend),this.errorHandler&&window.removeEventListener("error",this.errorHandler),this.rejectionHandler&&window.removeEventListener("unhandledrejection",this.rejectionHandler),this.initialized=!1}}};function L(n,t){return n?n.length>t?n.slice(0,t)+"\u2026":n:""}function vt(n){let t=[],e=n;for(;e&&e.nodeType===1;){let i=1,s=e.previousSibling;for(;s;)s.nodeType===1&&s.tagName===e.tagName&&i++,s=s.previousSibling;t.unshift(e.tagName.toLowerCase()+"["+i+"]"),e=e.parentElement}return"/"+t.join("/")}function xt(n){let t=n.tagName.toLowerCase();return!!(t==="input"||t==="textarea"||t==="select"||n.getAttribute("type")==="password"||n.getAttribute("data-no-capture")!==null||n.isContentEditable)}var S=class{constructor(t){this.active=!1;this.overlay=null;this.lastHighlighted=null;this.boundMove=null;this.boundClick=null;this.boundKey=null;this.transport=t}start(){this.active||(this.active=!0,this.overlay=document.createElement("div"),this.overlay.style.cssText="position:fixed;inset:0;z-index:999998;cursor:crosshair;background:transparent;",document.body.appendChild(this.overlay),this.boundMove=t=>this.onMouseMove(t),this.boundClick=t=>this.onClick(t),this.boundKey=t=>this.onKeyDown(t),document.addEventListener("mousemove",this.boundMove,!0),document.addEventListener("click",this.boundClick,!0),document.addEventListener("keydown",this.boundKey,!0))}stop(){this.active&&(this.transport.send(v),this.cleanup())}onMouseMove(t){if(!this.overlay)return;this.overlay.style.pointerEvents="none";let e=document.elementFromPoint(t.clientX,t.clientY);this.overlay.style.pointerEvents="auto",this.highlight(e)}onClick(t){if(t.preventDefault(),t.stopPropagation(),!this.overlay)return;this.overlay.style.pointerEvents="none";let e=document.elementFromPoint(t.clientX,t.clientY);if(this.overlay.style.pointerEvents="auto",!e||xt(e)){this.transport.send(v),this.cleanup();return}let i={};for(let a of["class","id","href","src","alt","title","data-id","data-name"]){let r=e.getAttribute(a);r&&(i[a]=L(r,200))}let s=e.parentElement?L(e.parentElement.innerText,300):"",o={elementText:L(e.innerText,500),elementTag:e.tagName.toLowerCase(),elementAttrs:i,surroundingText:s,xpath:vt(e)};this.transport.send(U,o),this.cleanup()}onKeyDown(t){t.key==="Escape"&&(this.transport.send(v),this.cleanup())}highlight(t){this.lastHighlighted&&(this.lastHighlighted.style.outline=this.lastHighlighted._prevOutline||"",this.lastHighlighted.style.outlineOffset=this.lastHighlighted._prevOffset||""),t&&t!==document.body&&t!==document.documentElement?(t._prevOutline=t.style.outline,t._prevOffset=t.style.outlineOffset,t.style.outline="2px solid #6366f1",t.style.outlineOffset="2px",this.lastHighlighted=t):this.lastHighlighted=null}cleanup(){var t,e;this.active=!1,this.lastHighlighted&&(this.lastHighlighted.style.outline=this.lastHighlighted._prevOutline||"",this.lastHighlighted.style.outlineOffset=this.lastHighlighted._prevOffset||""),(e=(t=this.overlay)==null?void 0:t.parentNode)==null||e.removeChild(this.overlay),this.overlay=null,this.boundMove&&document.removeEventListener("mousemove",this.boundMove,!0),this.boundClick&&document.removeEventListener("click",this.boundClick,!0),this.boundKey&&document.removeEventListener("keydown",this.boundKey,!0)}};function yt(n,t){return n?n.length>t?n.slice(0,t)+"\u2026":n:""}function J(n){let t={url:window.location.href,title:document.title||"",description:"",ogTitle:"",ogDescription:"",jsonLd:[],mainContent:"",customContext:{},lang:document.documentElement.lang||""},e=document.querySelector('meta[name="description"]');e&&(t.description=e.getAttribute("content")||"");let i=document.querySelector('meta[property="og:title"]');i&&(t.ogTitle=i.getAttribute("content")||"");let s=document.querySelector('meta[property="og:description"]');s&&(t.ogDescription=s.getAttribute("content")||"");try{document.querySelectorAll('script[type="application/ld+json"]').forEach(d=>{try{t.jsonLd.push(JSON.parse(d.textContent||""))}catch(p){}})}catch(r){}let o=document.querySelector("main, article, [role='main']");o&&(t.mainContent=yt(o.innerText,2e3));let a=document.querySelector(`script[data-key="${n}"]`);return a&&Array.from(a.attributes).forEach(r=>{if(r.name.startsWith("data-context-")){let d=r.name.replace("data-context-","").replace(/-/g,"_");t.customContext[d]=r.value}}),t}function tt(n,t){if(!t)return n;let e=h({},n);return t.pageType&&(e.pageType=t.pageType),t.visibleData&&(e.visibleData=t.visibleData),t.customContext&&(e.customContext=h(h({},e.customContext),t.customContext)),e}var b=class{constructor(t){this.lastUrl="";this.origPush=null;this.origReplace=null;this.popstateHandler=null;this.observer=null;this.onChange=t,this.lastUrl=window.location.href}start(){this.origPush=history.pushState,this.origReplace=history.replaceState;let t=this;history.pushState=function(...i){t.origPush.apply(this,i),t.checkChange()},history.replaceState=function(...i){t.origReplace.apply(this,i),t.checkChange()},this.popstateHandler=()=>this.checkChange(),window.addEventListener("popstate",this.popstateHandler);let e=document.querySelector("title");e&&(this.observer=new MutationObserver(()=>this.checkChange()),this.observer.observe(e,{childList:!0,characterData:!0,subtree:!0}))}destroy(){var t;this.origPush&&(history.pushState=this.origPush),this.origReplace&&(history.replaceState=this.origReplace),this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),(t=this.observer)==null||t.disconnect()}checkChange(){let t=window.location.href;t!==this.lastUrl&&(this.lastUrl=t,setTimeout(this.onChange,200))}};function M(){let n=getComputedStyle(document.body),t={bgColor:n.backgroundColor||"",fontFamily:n.fontFamily||"",textColor:n.color||"",primaryColor:"",accentColors:[]};try{let e=["a","button","h1","h2",".btn",".button",'[class*="primary"]'],i={};for(let o of e){let a=document.querySelectorAll(o);for(let r=0;r<Math.min(a.length,10);r++){let d=getComputedStyle(a[r]),p=d.color;p&&p!==t.textColor&&p!=="rgb(0, 0, 0)"&&p!=="rgba(0, 0, 0, 0)"&&(i[p]=(i[p]||0)+1);let c=d.backgroundColor;c&&c!=="rgba(0, 0, 0, 0)"&&c!=="transparent"&&c!==t.bgColor&&(i[c]=(i[c]||0)+1)}}let s=Object.keys(i).sort((o,a)=>i[a]-i[o]);t.primaryColor=s[0]||"",t.accentColors=s.slice(0,5)}catch(e){}return t}var wt=`
|
|
3
|
+
.max-widget-container{position:fixed;bottom:20px;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
|
|
4
|
+
.max-widget-container.right{right:20px}
|
|
5
|
+
.max-widget-container.left{left:20px}
|
|
6
|
+
.max-widget-btn{width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 12px rgba(0,0,0,0.3);transition:transform 0.2s,box-shadow 0.2s,opacity 0.2s}
|
|
7
|
+
.max-widget-btn:hover{transform:scale(1.05);box-shadow:0 6px 16px rgba(0,0,0,0.4)}
|
|
8
|
+
.max-widget-btn svg{width:24px;height:24px;fill:white}
|
|
9
|
+
.max-widget-frame{position:absolute;bottom:70px;width:380px;height:560px;border:none;border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,0.3);overflow:hidden;transition:opacity 0.2s,transform 0.2s;opacity:0;transform:translateY(10px) scale(0.95);pointer-events:none}
|
|
10
|
+
.max-widget-frame.right{right:0}
|
|
11
|
+
.max-widget-frame.left{left:0}
|
|
12
|
+
.max-widget-frame.open{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}
|
|
13
|
+
.max-widget-frame.expanded{position:fixed;top:0;bottom:0;width:440px;height:100vh;height:100dvh;border-radius:0;box-shadow:-4px 0 24px rgba(0,0,0,0.2);opacity:1;transform:translateX(0);pointer-events:auto;transition:transform 0.3s ease,width 0.3s ease,border-radius 0.3s ease,box-shadow 0.3s ease}
|
|
14
|
+
.max-widget-frame.expanded.right{right:0;left:auto}
|
|
15
|
+
.max-widget-frame.expanded.left{left:0;right:auto}
|
|
16
|
+
.max-widget-frame.expanded.panel-hidden.right{transform:translateX(100%)}
|
|
17
|
+
.max-widget-frame.expanded.panel-hidden.left{transform:translateX(-100%)}
|
|
18
|
+
.max-widget-container.panel-expanded .max-widget-btn{opacity:0;pointer-events:none;transform:scale(0.8)}
|
|
19
|
+
.max-widget-container.panel-hidden-state .max-widget-btn{opacity:0;pointer-events:none;transform:scale(0.8)}
|
|
20
|
+
.max-widget-tab{position:fixed;top:12px;z-index:999999;width:40px;height:40px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:-2px 2px 8px rgba(0,0,0,0.2);transition:opacity 0.2s,transform 0.2s;opacity:0;pointer-events:none;transform:translateX(8px)}
|
|
21
|
+
.max-widget-tab.right{right:0;border-radius:8px 0 0 8px}
|
|
22
|
+
.max-widget-tab.left{left:0;border-radius:0 8px 8px 0}
|
|
23
|
+
.max-widget-tab.left{transform:translateX(-8px)}
|
|
24
|
+
.max-widget-tab.visible{opacity:1;pointer-events:auto;transform:translateX(0)}
|
|
25
|
+
.max-widget-tab:hover{filter:brightness(1.1)}
|
|
26
|
+
.max-widget-tab svg{width:18px;height:18px;fill:white}
|
|
27
|
+
@media(max-width:420px){.max-widget-frame{width:calc(100vw - 40px);height:calc(100vh - 120px)}}
|
|
28
|
+
@media(max-width:420px){.max-widget-frame.expanded{width:100vw}}
|
|
29
|
+
`,C='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>',A='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',Et='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>',St='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>';function et(n,t,e,i,s,o){let a=document.createElement("style");s&&(a.nonce=s),a.textContent=wt,document.head.appendChild(a);let r=document.createElement("div");r.className="max-widget-container "+(e?"right":"left"),document.body.appendChild(r);let d=document.createElement("iframe");d.className="max-widget-frame "+(e?"right":"left"),d.src=n+"/widget/"+t,d.setAttribute("allow","clipboard-write"),r.appendChild(d);let p=document.createElement("button");p.className="max-widget-btn",p.style.backgroundColor=i,p.innerHTML=C,r.appendChild(p);let c=document.createElement("button");c.className="max-widget-tab "+(e?"right":"left"),c.style.backgroundColor=i,c.innerHTML=e?Et:St,document.body.appendChild(c);let _=!1,O=!1;function at(){O=!1,d.classList.remove("expanded","panel-hidden"),r.classList.remove("panel-expanded","panel-hidden-state"),c.classList.remove("visible"),d.style.position="",d.style.top="",d.style.bottom="",document.body.style.overflow=""}return p.addEventListener("click",()=>{if(O){at();return}_=!_,_?(d.classList.add("open"),p.innerHTML=A,o.onOpen()):(d.classList.remove("open"),p.innerHTML=C,o.onClose())}),c.addEventListener("click",()=>{d.classList.remove("panel-hidden"),r.classList.remove("panel-hidden-state"),c.classList.remove("visible")}),{container:r,iframe:d,btn:p,tab:c,style:a}}function nt(n,t,e){let{container:i,iframe:s,btn:o,tab:a}=n;t?(s.classList.contains("open")||(s.classList.add("open"),o.innerHTML=A),s.classList.add("expanded"),i.classList.add("panel-expanded"),s.classList.remove("panel-hidden"),i.classList.remove("panel-hidden-state"),a.classList.remove("visible"),window.innerWidth<=420&&(document.body.style.overflow="hidden")):(s.classList.remove("expanded","panel-hidden"),i.classList.remove("panel-expanded","panel-hidden-state"),a.classList.remove("visible"),s.style.position="",s.style.top="",s.style.bottom="",document.body.style.overflow="")}function it(n){n.iframe.classList.add("panel-hidden"),n.container.classList.add("panel-hidden-state"),n.tab.classList.add("visible")}function st(n){n.container.remove(),n.tab.remove(),n.style.remove()}function ot(n){n.iframe.classList.add("open"),n.btn.innerHTML=A}function rt(n){n.iframe.classList.remove("open"),n.btn.innerHTML=C}var T=class{constructor(t){this.emitter=new m;this.debug=new E;this.ui=null;this.explicitContext=null;this.consentGiven=!1;this.config=null;this.key=t.key,this.isRight=t.position!=="bottom-left",this.nonce=t.nonce||null;let e=document.querySelector(`script[data-key="${t.key}"]`);e&&e.src?this.baseUrl=e.src.replace(/\/(widget-embed\.js|sdk\.js).*$/,""):t.baseUrl?this.baseUrl=t.baseUrl:this.baseUrl="https://maxaiagent.app",this.transport=new g(this.baseUrl),this.tools=new y(this.transport),this.pointAndAsk=new S(this.transport),this.spaDetector=new b(()=>this.sendPageContext()),this.init()}async init(){let t;try{t=await(await fetch(`${this.baseUrl}/api/widget/config/${this.key}`)).json()}catch(i){t={}}this.config={pageContext:t.enable_page_context||!1,pointAndAsk:t.enable_point_and_ask||!1,debugMode:t.enable_debug_mode||!1,bugReport:t.enable_bug_reports||!1,clientTools:t.enable_client_tools||!1,autoTheme:t.theme_mode!=="manual",themeMode:t.theme_mode||"manual",gdprRequired:t.gdpr_consent_required||!1},this.spaDetector.start(),this.config.debugMode&&(!this.config.gdprRequired||this.consentGiven)&&this.debug.init();let e=t.primary_color||"#6366f1";this.ui=et(this.baseUrl,this.key,this.isRight,e,this.nonce,{onOpen:()=>this.emitter.emit("open"),onClose:()=>this.emitter.emit("close")}),this.transport.attach(this.ui.iframe),this.ui.iframe.addEventListener("load",()=>{var i,s;this.transport.markReady(),this.config&&this.transport.send(X,{features:this.config}),(!((i=this.config)!=null&&i.gdprRequired)||this.consentGiven)&&(this.sendPageContext(),(s=this.config)!=null&&s.autoTheme&&this.transport.send(x,{styles:M()})),this.tools.hasTools()&&this.tools.sendList(),this.emitter.emit("ready")}),this.setupMessageHandlers()}setupMessageHandlers(){this.transport.listen(q,t=>{this.ui&&nt(this.ui,!!t.expanded,this.isRight)}),this.transport.listen(z,()=>{this.ui&&it(this.ui)}),this.transport.listen(W,()=>{this.sendPageContext()}),this.transport.listen(K,()=>{this.pointAndAsk.start()}),this.transport.listen(j,()=>{this.pointAndAsk.stop()}),this.transport.listen(F,t=>{let{toolCallId:e,name:i,args:s}=t;this.emitter.emit("tool:call",{id:e,name:i,args:s}),this.tools.execute(e,i,s).then(()=>{this.emitter.emit("tool:result",{id:e,name:i,ok:!0})})}),this.transport.listen(B,()=>{this.transport.send(N,{snapshot:this.debug.getSnapshot()})}),this.transport.listen(Y,()=>{this.transport.send(x,{styles:M()})}),this.transport.listen($,()=>{var t,e;this.consentGiven=!0,this.sendPageContext(),(t=this.config)!=null&&t.debugMode&&this.debug.init(),(e=this.config)!=null&&e.autoTheme&&this.transport.send(x,{styles:M()})}),this.transport.listen(Z,t=>{if(t.url)try{window.location.href=t.url}catch(e){}}),this.transport.listen(Q,t=>{this.emitter.emit("message",t.message)}),this.transport.listen(V,t=>{this.emitter.emit("error",{message:t.error})})}sendPageContext(){var i;if(!this.consentGiven&&((i=this.config)!=null&&i.gdprRequired))return;let t=J(this.key),e=tt(t,this.explicitContext);this.transport.send(I,{context:e})}setPageContext(t){this.explicitContext=t,this.sendPageContext()}registerTool(t){return this.tools.register(t)}unregisterTool(t){this.tools.unregister(t)}on(t,e){return this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}open(){this.ui&&(ot(this.ui),this.emitter.emit("open"))}close(){this.ui&&(rt(this.ui),this.emitter.emit("close"))}destroy(){this.spaDetector.destroy(),this.debug.destroy(),this.tools.destroy(),this.transport.destroy(),this.emitter.removeAll(),this.ui&&st(this.ui),this.ui=null}};var l=null,H={init(n){return l?(console.warn("[MaxAI SDK] Already initialized. Call destroy() first to reinitialize."),l):(l=new T(n),l)},setPageContext(n){if(!l){console.warn("[MaxAI SDK] Not initialized. Call MaxAI.init() first.");return}l.setPageContext(n)},registerTool(n){return l?l.registerTool(n):(console.warn("[MaxAI SDK] Not initialized. Call MaxAI.init() first."),()=>{})},unregisterTool(n){l&&l.unregisterTool(n)},on(n,t){return l?l.on(n,t):(console.warn("[MaxAI SDK] Not initialized."),()=>{})},open(){l==null||l.open()},close(){l==null||l.close()},destroy(){l==null||l.destroy(),l=null},_initialized:!1};if(typeof document!="undefined"){let n=document.currentScript;if(n){let t=n.getAttribute("data-key");t&&H.init({key:t,position:n.getAttribute("data-position")||"bottom-right",nonce:n.getAttribute("data-nonce")||void 0,lazy:n.getAttribute("data-lazy")==="true",baseUrl:n.src?n.src.replace(/\/(sdk|widget-embed)\.js.*$/,""):void 0})}}typeof window!="undefined"&&(window.MaxAI=H);return ut(bt);})();
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* @maxai/widget-sdk v1.0.0 | MIT License | maxaiagent.app */
|
|
2
|
+
var rt=Object.defineProperty;var H=Object.getOwnPropertySymbols;var at=Object.prototype.hasOwnProperty,lt=Object.prototype.propertyIsEnumerable;var O=(n,t,e)=>t in n?rt(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e,h=(n,t)=>{for(var e in t||(t={}))at.call(t,e)&&O(n,e,t[e]);if(H)for(var e of H(t))lt.call(t,e)&&O(n,e,t[e]);return n};var u=class{constructor(t){this.iframe=null;this.ready=!1;this.queue=[];this.handlers=new Map;this.boundListener=null;this.baseUrl=t}attach(t){this.iframe=t,this.boundListener=e=>this.onMessage(e),window.addEventListener("message",this.boundListener)}markReady(){this.ready=!0;for(let t of this.queue)this.sendRaw(t);this.queue=[]}send(t,e){let i=h({type:t},e);this.ready&&this.iframe?this.sendRaw(i):this.queue.push(i)}listen(t,e){this.handlers.set(t,e)}destroy(){this.boundListener&&(window.removeEventListener("message",this.boundListener),this.boundListener=null),this.handlers.clear(),this.queue=[],this.iframe=null,this.ready=!1}sendRaw(t){var e,i;try{(i=(e=this.iframe)==null?void 0:e.contentWindow)==null||i.postMessage(t,this.baseUrl||"*")}catch(s){}}onMessage(t){if(!t.data||!t.data.type||this.iframe&&t.source!==this.iframe.contentWindow)return;let e=this.handlers.get(t.data.type);e&&e(t.data)}};var g=class{constructor(){this.listeners=new Map}on(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>this.off(t,e)}off(t,e){var i;(i=this.listeners.get(t))==null||i.delete(e)}emit(t,...e){var i;(i=this.listeners.get(t))==null||i.forEach(s=>{try{s(...e)}catch(o){console.error("[MaxAI SDK]",o)}})}removeAll(){this.listeners.clear()}};var R="max-widget:page-context",k="max-widget:register-tools",G="max-widget:unregister-tool",m="max-widget:tool-result",I="max-widget:point-ask-result",f="max-widget:point-ask-cancel",v="max-widget:host-styles",P="max-widget:debug-snapshot",D="max-widget:config-features";var U="max-widget:expand",N="max-widget:hide",X="max-widget:request-page-context",q="max-widget:start-point-ask",z="max-widget:stop-point-ask",W="max-widget:execute-tool",K="max-widget:request-debug-snapshot",j="max-widget:request-host-styles",F="max-widget:gdpr-consent",B="max-widget:navigate",Y="max-widget:message",$="max-widget:error";var x=class{constructor(t){this.tools=new Map;this.transport=t}register(t){return!t.name||!/^[a-zA-Z0-9_]+$/.test(t.name)?(console.error("[MaxAI SDK] Invalid tool name:",t.name),()=>{}):(this.tools.set(t.name,h({},t)),this.sendList(),()=>this.unregister(t.name))}unregister(t){this.tools.has(t)&&(this.tools.delete(t),this.transport.send(G,{name:t}),this.sendList())}async execute(t,e,i){let s=this.tools.get(e);if(!(s!=null&&s.handler)){this.transport.send(m,{toolCallId:t,ok:!1,error:`Tool "${e}" not found or has no handler`});return}try{let o=await s.handler(i);this.transport.send(m,{toolCallId:t,ok:!0,data:o}),window.dispatchEvent(new CustomEvent("MaxAI:DataMutated",{detail:{toolName:e,args:i}}))}catch(o){this.transport.send(m,{toolCallId:t,ok:!1,error:o instanceof Error?o.message:"Tool execution failed"})}}sendList(){let t=Array.from(this.tools.values()).map(e=>({name:e.name,description:e.description,schema:e.schema,requiresConfirmation:e.requiresConfirmation||!1,category:e.category||""}));this.transport.send(k,{tools:t})}hasTools(){return this.tools.size>0}destroy(){this.tools.clear()}};function y(n,t){return n.length>t?n.slice(0,t)+"\u2026":n}var pt=[/Bearer\s+[A-Za-z0-9\-._~+/]+=*/g,/token=[A-Za-z0-9\-._~+/]+=*/g,/password["'\s:=]+["']?[^\s"',}]*/gi,/api[_-]?key["'\s:=]+["']?[A-Za-z0-9\-._~+/]*/gi,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g];function ct(n){let t=JSON.stringify(n);for(let e of pt)t=t.replace(e,"[REDACTED]");try{return JSON.parse(t)}catch(e){return n}}var w=class{constructor(){this.consoleLogs=[];this.networkLog=[];this.errors=[];this.origConsole={};this.origFetch=null;this.origXHROpen=null;this.origXHRSend=null;this.errorHandler=null;this.rejectionHandler=null;this.initialized=!1}init(){if(this.initialized)return;this.initialized=!0;for(let e of["log","warn","error"])this.origConsole[e]=console[e].bind(console),console[e]=(...i)=>{this.origConsole[e](...i);try{let s=i.map(o=>{try{return typeof o=="string"?o:JSON.stringify(o)}catch(a){return String(o)}}).join(" ");this.consoleLogs.push({level:e,message:y(s,500),timestamp:Date.now()}),this.consoleLogs.length>50&&this.consoleLogs.shift()}catch(s){}};this.errorHandler=e=>{this.errors.push({message:e.message||"",source:e.filename||"",line:e.lineno||0,col:e.colno||0,timestamp:Date.now()}),this.errors.length>50&&this.errors.shift()},window.addEventListener("error",this.errorHandler),this.rejectionHandler=e=>{this.errors.push({message:"Unhandled rejection: "+(e.reason?String(e.reason):"unknown"),timestamp:Date.now()}),this.errors.length>50&&this.errors.shift()},window.addEventListener("unhandledrejection",this.rejectionHandler),this.origFetch=window.fetch,window.fetch=(...e)=>{let i=e[0],o=((e[1]||{}).method||"GET").toUpperCase(),a=Date.now();return this.origFetch(...e).then(r=>(this.networkLog.push({method:o,url:typeof i=="string"?y(i,200):"(Request)",status:r.status,duration:Date.now()-a,timestamp:a}),this.networkLog.length>30&&this.networkLog.shift(),r)).catch(r=>{throw this.networkLog.push({method:o,url:typeof i=="string"?y(i,200):"(Request)",status:0,error:r.message||"Network error",duration:Date.now()-a,timestamp:a}),this.networkLog.length>30&&this.networkLog.shift(),r})},this.origXHROpen=XMLHttpRequest.prototype.open,this.origXHRSend=XMLHttpRequest.prototype.send;let t=this;XMLHttpRequest.prototype.open=function(e,i){return this._m=e,this._u=String(i),this._t=Date.now(),t.origXHROpen.apply(this,arguments)},XMLHttpRequest.prototype.send=function(){let e=this;return e.addEventListener("loadend",()=>{t.networkLog.push({method:(e._m||"GET").toUpperCase(),url:y(e._u||"",200),status:e.status,duration:Date.now()-(e._t||Date.now()),timestamp:e._t||Date.now()}),t.networkLog.length>30&&t.networkLog.shift()}),t.origXHRSend.apply(this,arguments)}}getSnapshot(){return ct({consoleLogs:this.consoleLogs.slice(),networkLog:this.networkLog.slice(),errors:this.errors.slice(),pageUrl:window.location.href,timestamp:Date.now()})}destroy(){if(this.initialized){for(let t of Object.keys(this.origConsole))console[t]=this.origConsole[t];this.origFetch&&(window.fetch=this.origFetch),this.origXHROpen&&(XMLHttpRequest.prototype.open=this.origXHROpen),this.origXHRSend&&(XMLHttpRequest.prototype.send=this.origXHRSend),this.errorHandler&&window.removeEventListener("error",this.errorHandler),this.rejectionHandler&&window.removeEventListener("unhandledrejection",this.rejectionHandler),this.initialized=!1}}};function _(n,t){return n?n.length>t?n.slice(0,t)+"\u2026":n:""}function ht(n){let t=[],e=n;for(;e&&e.nodeType===1;){let i=1,s=e.previousSibling;for(;s;)s.nodeType===1&&s.tagName===e.tagName&&i++,s=s.previousSibling;t.unshift(e.tagName.toLowerCase()+"["+i+"]"),e=e.parentElement}return"/"+t.join("/")}function ut(n){let t=n.tagName.toLowerCase();return!!(t==="input"||t==="textarea"||t==="select"||n.getAttribute("type")==="password"||n.getAttribute("data-no-capture")!==null||n.isContentEditable)}var E=class{constructor(t){this.active=!1;this.overlay=null;this.lastHighlighted=null;this.boundMove=null;this.boundClick=null;this.boundKey=null;this.transport=t}start(){this.active||(this.active=!0,this.overlay=document.createElement("div"),this.overlay.style.cssText="position:fixed;inset:0;z-index:999998;cursor:crosshair;background:transparent;",document.body.appendChild(this.overlay),this.boundMove=t=>this.onMouseMove(t),this.boundClick=t=>this.onClick(t),this.boundKey=t=>this.onKeyDown(t),document.addEventListener("mousemove",this.boundMove,!0),document.addEventListener("click",this.boundClick,!0),document.addEventListener("keydown",this.boundKey,!0))}stop(){this.active&&(this.transport.send(f),this.cleanup())}onMouseMove(t){if(!this.overlay)return;this.overlay.style.pointerEvents="none";let e=document.elementFromPoint(t.clientX,t.clientY);this.overlay.style.pointerEvents="auto",this.highlight(e)}onClick(t){if(t.preventDefault(),t.stopPropagation(),!this.overlay)return;this.overlay.style.pointerEvents="none";let e=document.elementFromPoint(t.clientX,t.clientY);if(this.overlay.style.pointerEvents="auto",!e||ut(e)){this.transport.send(f),this.cleanup();return}let i={};for(let a of["class","id","href","src","alt","title","data-id","data-name"]){let r=e.getAttribute(a);r&&(i[a]=_(r,200))}let s=e.parentElement?_(e.parentElement.innerText,300):"",o={elementText:_(e.innerText,500),elementTag:e.tagName.toLowerCase(),elementAttrs:i,surroundingText:s,xpath:ht(e)};this.transport.send(I,o),this.cleanup()}onKeyDown(t){t.key==="Escape"&&(this.transport.send(f),this.cleanup())}highlight(t){this.lastHighlighted&&(this.lastHighlighted.style.outline=this.lastHighlighted._prevOutline||"",this.lastHighlighted.style.outlineOffset=this.lastHighlighted._prevOffset||""),t&&t!==document.body&&t!==document.documentElement?(t._prevOutline=t.style.outline,t._prevOffset=t.style.outlineOffset,t.style.outline="2px solid #6366f1",t.style.outlineOffset="2px",this.lastHighlighted=t):this.lastHighlighted=null}cleanup(){var t,e;this.active=!1,this.lastHighlighted&&(this.lastHighlighted.style.outline=this.lastHighlighted._prevOutline||"",this.lastHighlighted.style.outlineOffset=this.lastHighlighted._prevOffset||""),(e=(t=this.overlay)==null?void 0:t.parentNode)==null||e.removeChild(this.overlay),this.overlay=null,this.boundMove&&document.removeEventListener("mousemove",this.boundMove,!0),this.boundClick&&document.removeEventListener("click",this.boundClick,!0),this.boundKey&&document.removeEventListener("keydown",this.boundKey,!0)}};function gt(n,t){return n?n.length>t?n.slice(0,t)+"\u2026":n:""}function Z(n){let t={url:window.location.href,title:document.title||"",description:"",ogTitle:"",ogDescription:"",jsonLd:[],mainContent:"",customContext:{},lang:document.documentElement.lang||""},e=document.querySelector('meta[name="description"]');e&&(t.description=e.getAttribute("content")||"");let i=document.querySelector('meta[property="og:title"]');i&&(t.ogTitle=i.getAttribute("content")||"");let s=document.querySelector('meta[property="og:description"]');s&&(t.ogDescription=s.getAttribute("content")||"");try{document.querySelectorAll('script[type="application/ld+json"]').forEach(d=>{try{t.jsonLd.push(JSON.parse(d.textContent||""))}catch(p){}})}catch(r){}let o=document.querySelector("main, article, [role='main']");o&&(t.mainContent=gt(o.innerText,2e3));let a=document.querySelector(`script[data-key="${n}"]`);return a&&Array.from(a.attributes).forEach(r=>{if(r.name.startsWith("data-context-")){let d=r.name.replace("data-context-","").replace(/-/g,"_");t.customContext[d]=r.value}}),t}function Q(n,t){if(!t)return n;let e=h({},n);return t.pageType&&(e.pageType=t.pageType),t.visibleData&&(e.visibleData=t.visibleData),t.customContext&&(e.customContext=h(h({},e.customContext),t.customContext)),e}var S=class{constructor(t){this.lastUrl="";this.origPush=null;this.origReplace=null;this.popstateHandler=null;this.observer=null;this.onChange=t,this.lastUrl=window.location.href}start(){this.origPush=history.pushState,this.origReplace=history.replaceState;let t=this;history.pushState=function(...i){t.origPush.apply(this,i),t.checkChange()},history.replaceState=function(...i){t.origReplace.apply(this,i),t.checkChange()},this.popstateHandler=()=>this.checkChange(),window.addEventListener("popstate",this.popstateHandler);let e=document.querySelector("title");e&&(this.observer=new MutationObserver(()=>this.checkChange()),this.observer.observe(e,{childList:!0,characterData:!0,subtree:!0}))}destroy(){var t;this.origPush&&(history.pushState=this.origPush),this.origReplace&&(history.replaceState=this.origReplace),this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),(t=this.observer)==null||t.disconnect()}checkChange(){let t=window.location.href;t!==this.lastUrl&&(this.lastUrl=t,setTimeout(this.onChange,200))}};function b(){let n=getComputedStyle(document.body),t={bgColor:n.backgroundColor||"",fontFamily:n.fontFamily||"",textColor:n.color||"",primaryColor:"",accentColors:[]};try{let e=["a","button","h1","h2",".btn",".button",'[class*="primary"]'],i={};for(let o of e){let a=document.querySelectorAll(o);for(let r=0;r<Math.min(a.length,10);r++){let d=getComputedStyle(a[r]),p=d.color;p&&p!==t.textColor&&p!=="rgb(0, 0, 0)"&&p!=="rgba(0, 0, 0, 0)"&&(i[p]=(i[p]||0)+1);let c=d.backgroundColor;c&&c!=="rgba(0, 0, 0, 0)"&&c!=="transparent"&&c!==t.bgColor&&(i[c]=(i[c]||0)+1)}}let s=Object.keys(i).sort((o,a)=>i[a]-i[o]);t.primaryColor=s[0]||"",t.accentColors=s.slice(0,5)}catch(e){}return t}var mt=`
|
|
3
|
+
.max-widget-container{position:fixed;bottom:20px;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
|
|
4
|
+
.max-widget-container.right{right:20px}
|
|
5
|
+
.max-widget-container.left{left:20px}
|
|
6
|
+
.max-widget-btn{width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 12px rgba(0,0,0,0.3);transition:transform 0.2s,box-shadow 0.2s,opacity 0.2s}
|
|
7
|
+
.max-widget-btn:hover{transform:scale(1.05);box-shadow:0 6px 16px rgba(0,0,0,0.4)}
|
|
8
|
+
.max-widget-btn svg{width:24px;height:24px;fill:white}
|
|
9
|
+
.max-widget-frame{position:absolute;bottom:70px;width:380px;height:560px;border:none;border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,0.3);overflow:hidden;transition:opacity 0.2s,transform 0.2s;opacity:0;transform:translateY(10px) scale(0.95);pointer-events:none}
|
|
10
|
+
.max-widget-frame.right{right:0}
|
|
11
|
+
.max-widget-frame.left{left:0}
|
|
12
|
+
.max-widget-frame.open{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}
|
|
13
|
+
.max-widget-frame.expanded{position:fixed;top:0;bottom:0;width:440px;height:100vh;height:100dvh;border-radius:0;box-shadow:-4px 0 24px rgba(0,0,0,0.2);opacity:1;transform:translateX(0);pointer-events:auto;transition:transform 0.3s ease,width 0.3s ease,border-radius 0.3s ease,box-shadow 0.3s ease}
|
|
14
|
+
.max-widget-frame.expanded.right{right:0;left:auto}
|
|
15
|
+
.max-widget-frame.expanded.left{left:0;right:auto}
|
|
16
|
+
.max-widget-frame.expanded.panel-hidden.right{transform:translateX(100%)}
|
|
17
|
+
.max-widget-frame.expanded.panel-hidden.left{transform:translateX(-100%)}
|
|
18
|
+
.max-widget-container.panel-expanded .max-widget-btn{opacity:0;pointer-events:none;transform:scale(0.8)}
|
|
19
|
+
.max-widget-container.panel-hidden-state .max-widget-btn{opacity:0;pointer-events:none;transform:scale(0.8)}
|
|
20
|
+
.max-widget-tab{position:fixed;top:12px;z-index:999999;width:40px;height:40px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:-2px 2px 8px rgba(0,0,0,0.2);transition:opacity 0.2s,transform 0.2s;opacity:0;pointer-events:none;transform:translateX(8px)}
|
|
21
|
+
.max-widget-tab.right{right:0;border-radius:8px 0 0 8px}
|
|
22
|
+
.max-widget-tab.left{left:0;border-radius:0 8px 8px 0}
|
|
23
|
+
.max-widget-tab.left{transform:translateX(-8px)}
|
|
24
|
+
.max-widget-tab.visible{opacity:1;pointer-events:auto;transform:translateX(0)}
|
|
25
|
+
.max-widget-tab:hover{filter:brightness(1.1)}
|
|
26
|
+
.max-widget-tab svg{width:18px;height:18px;fill:white}
|
|
27
|
+
@media(max-width:420px){.max-widget-frame{width:calc(100vw - 40px);height:calc(100vh - 120px)}}
|
|
28
|
+
@media(max-width:420px){.max-widget-frame.expanded{width:100vw}}
|
|
29
|
+
`,L='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>',C='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',ft='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>',vt='<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>';function V(n,t,e,i,s,o){let a=document.createElement("style");s&&(a.nonce=s),a.textContent=mt,document.head.appendChild(a);let r=document.createElement("div");r.className="max-widget-container "+(e?"right":"left"),document.body.appendChild(r);let d=document.createElement("iframe");d.className="max-widget-frame "+(e?"right":"left"),d.src=n+"/widget/"+t,d.setAttribute("allow","clipboard-write"),r.appendChild(d);let p=document.createElement("button");p.className="max-widget-btn",p.style.backgroundColor=i,p.innerHTML=L,r.appendChild(p);let c=document.createElement("button");c.className="max-widget-tab "+(e?"right":"left"),c.style.backgroundColor=i,c.innerHTML=e?ft:vt,document.body.appendChild(c);let T=!1,A=!1;function ot(){A=!1,d.classList.remove("expanded","panel-hidden"),r.classList.remove("panel-expanded","panel-hidden-state"),c.classList.remove("visible"),d.style.position="",d.style.top="",d.style.bottom="",document.body.style.overflow=""}return p.addEventListener("click",()=>{if(A){ot();return}T=!T,T?(d.classList.add("open"),p.innerHTML=C,o.onOpen()):(d.classList.remove("open"),p.innerHTML=L,o.onClose())}),c.addEventListener("click",()=>{d.classList.remove("panel-hidden"),r.classList.remove("panel-hidden-state"),c.classList.remove("visible")}),{container:r,iframe:d,btn:p,tab:c,style:a}}function J(n,t,e){let{container:i,iframe:s,btn:o,tab:a}=n;t?(s.classList.contains("open")||(s.classList.add("open"),o.innerHTML=C),s.classList.add("expanded"),i.classList.add("panel-expanded"),s.classList.remove("panel-hidden"),i.classList.remove("panel-hidden-state"),a.classList.remove("visible"),window.innerWidth<=420&&(document.body.style.overflow="hidden")):(s.classList.remove("expanded","panel-hidden"),i.classList.remove("panel-expanded","panel-hidden-state"),a.classList.remove("visible"),s.style.position="",s.style.top="",s.style.bottom="",document.body.style.overflow="")}function tt(n){n.iframe.classList.add("panel-hidden"),n.container.classList.add("panel-hidden-state"),n.tab.classList.add("visible")}function et(n){n.container.remove(),n.tab.remove(),n.style.remove()}function nt(n){n.iframe.classList.add("open"),n.btn.innerHTML=C}function it(n){n.iframe.classList.remove("open"),n.btn.innerHTML=L}var M=class{constructor(t){this.emitter=new g;this.debug=new w;this.ui=null;this.explicitContext=null;this.consentGiven=!1;this.config=null;this.key=t.key,this.isRight=t.position!=="bottom-left",this.nonce=t.nonce||null;let e=document.querySelector(`script[data-key="${t.key}"]`);e&&e.src?this.baseUrl=e.src.replace(/\/(widget-embed\.js|sdk\.js).*$/,""):t.baseUrl?this.baseUrl=t.baseUrl:this.baseUrl="https://maxaiagent.app",this.transport=new u(this.baseUrl),this.tools=new x(this.transport),this.pointAndAsk=new E(this.transport),this.spaDetector=new S(()=>this.sendPageContext()),this.init()}async init(){let t;try{t=await(await fetch(`${this.baseUrl}/api/widget/config/${this.key}`)).json()}catch(i){t={}}this.config={pageContext:t.enable_page_context||!1,pointAndAsk:t.enable_point_and_ask||!1,debugMode:t.enable_debug_mode||!1,bugReport:t.enable_bug_reports||!1,clientTools:t.enable_client_tools||!1,autoTheme:t.theme_mode!=="manual",themeMode:t.theme_mode||"manual",gdprRequired:t.gdpr_consent_required||!1},this.spaDetector.start(),this.config.debugMode&&(!this.config.gdprRequired||this.consentGiven)&&this.debug.init();let e=t.primary_color||"#6366f1";this.ui=V(this.baseUrl,this.key,this.isRight,e,this.nonce,{onOpen:()=>this.emitter.emit("open"),onClose:()=>this.emitter.emit("close")}),this.transport.attach(this.ui.iframe),this.ui.iframe.addEventListener("load",()=>{var i,s;this.transport.markReady(),this.config&&this.transport.send(D,{features:this.config}),(!((i=this.config)!=null&&i.gdprRequired)||this.consentGiven)&&(this.sendPageContext(),(s=this.config)!=null&&s.autoTheme&&this.transport.send(v,{styles:b()})),this.tools.hasTools()&&this.tools.sendList(),this.emitter.emit("ready")}),this.setupMessageHandlers()}setupMessageHandlers(){this.transport.listen(U,t=>{this.ui&&J(this.ui,!!t.expanded,this.isRight)}),this.transport.listen(N,()=>{this.ui&&tt(this.ui)}),this.transport.listen(X,()=>{this.sendPageContext()}),this.transport.listen(q,()=>{this.pointAndAsk.start()}),this.transport.listen(z,()=>{this.pointAndAsk.stop()}),this.transport.listen(W,t=>{let{toolCallId:e,name:i,args:s}=t;this.emitter.emit("tool:call",{id:e,name:i,args:s}),this.tools.execute(e,i,s).then(()=>{this.emitter.emit("tool:result",{id:e,name:i,ok:!0})})}),this.transport.listen(K,()=>{this.transport.send(P,{snapshot:this.debug.getSnapshot()})}),this.transport.listen(j,()=>{this.transport.send(v,{styles:b()})}),this.transport.listen(F,()=>{var t,e;this.consentGiven=!0,this.sendPageContext(),(t=this.config)!=null&&t.debugMode&&this.debug.init(),(e=this.config)!=null&&e.autoTheme&&this.transport.send(v,{styles:b()})}),this.transport.listen(B,t=>{if(t.url)try{window.location.href=t.url}catch(e){}}),this.transport.listen(Y,t=>{this.emitter.emit("message",t.message)}),this.transport.listen($,t=>{this.emitter.emit("error",{message:t.error})})}sendPageContext(){var i;if(!this.consentGiven&&((i=this.config)!=null&&i.gdprRequired))return;let t=Z(this.key),e=Q(t,this.explicitContext);this.transport.send(R,{context:e})}setPageContext(t){this.explicitContext=t,this.sendPageContext()}registerTool(t){return this.tools.register(t)}unregisterTool(t){this.tools.unregister(t)}on(t,e){return this.emitter.on(t,e)}off(t,e){this.emitter.off(t,e)}open(){this.ui&&(nt(this.ui),this.emitter.emit("open"))}close(){this.ui&&(it(this.ui),this.emitter.emit("close"))}destroy(){this.spaDetector.destroy(),this.debug.destroy(),this.tools.destroy(),this.transport.destroy(),this.emitter.removeAll(),this.ui&&et(this.ui),this.ui=null}};var l=null,st={init(n){return l?(console.warn("[MaxAI SDK] Already initialized. Call destroy() first to reinitialize."),l):(l=new M(n),l)},setPageContext(n){if(!l){console.warn("[MaxAI SDK] Not initialized. Call MaxAI.init() first.");return}l.setPageContext(n)},registerTool(n){return l?l.registerTool(n):(console.warn("[MaxAI SDK] Not initialized. Call MaxAI.init() first."),()=>{})},unregisterTool(n){l&&l.unregisterTool(n)},on(n,t){return l?l.on(n,t):(console.warn("[MaxAI SDK] Not initialized."),()=>{})},open(){l==null||l.open()},close(){l==null||l.close()},destroy(){l==null||l.destroy(),l=null},_initialized:!1};if(typeof document!="undefined"){let n=document.currentScript;if(n){let t=n.getAttribute("data-key");t&&st.init({key:t,position:n.getAttribute("data-position")||"bottom-right",nonce:n.getAttribute("data-nonce")||void 0,lazy:n.getAttribute("data-lazy")==="true",baseUrl:n.src?n.src.replace(/\/(sdk|widget-embed)\.js.*$/,""):void 0})}}typeof window!="undefined"&&(window.MaxAI=st);export{st as MaxAI};
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maxaiagent/widget-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MaxAI Widget SDK — embed AI chat with page context, client-side tools, and event system",
|
|
5
|
+
"main": "dist/index.global.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.global.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"postbuild": "cp dist/index.global.js ../../public/sdk.js"
|
|
19
|
+
},
|
|
20
|
+
"keywords": ["maxai", "widget", "chat", "ai", "sdk"],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"tsup": "^8.0.0",
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|