wakz-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 +264 -0
- package/dist/client.d.ts +124 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +323 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto.d.ts +26 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +161 -0
- package/dist/crypto.js.map +1 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/client.mjs +319 -0
- package/dist/esm/crypto.js.map +1 -0
- package/dist/esm/crypto.mjs +123 -0
- package/dist/esm/events.js.map +1 -0
- package/dist/esm/events.mjs +100 -0
- package/dist/esm/http.js.map +1 -0
- package/dist/esm/http.mjs +159 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/index.mjs +32 -0
- package/dist/esm/session.js.map +1 -0
- package/dist/esm/session.mjs +186 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/types.mjs +5 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/utils.mjs +139 -0
- package/dist/esm/websocket.js.map +1 -0
- package/dist/esm/websocket.mjs +363 -0
- package/dist/events.d.ts +38 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +104 -0
- package/dist/events.js.map +1 -0
- package/dist/http.d.ts +37 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +163 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +75 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +190 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +56 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +153 -0
- package/dist/utils.js.map +1 -0
- package/dist/websocket.d.ts +93 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +367 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// WAKZ SDK — WebSocket Transport Manager
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
import { WAKZEventEmitter } from './events';
|
|
5
|
+
import { calculateBackoff, sleep, nowISO, generateId, Logger } from './utils';
|
|
6
|
+
/**
|
|
7
|
+
* WebSocket transport manager with automatic reconnection.
|
|
8
|
+
* Handles connection lifecycle, message framing, and keep-alive.
|
|
9
|
+
*/
|
|
10
|
+
export class WebSocketTransport extends WAKZEventEmitter {
|
|
11
|
+
// Re-export connected state
|
|
12
|
+
get isConnected() {
|
|
13
|
+
return this._isConnected && this.ws?.readyState === WebSocket.OPEN;
|
|
14
|
+
}
|
|
15
|
+
constructor(apiKey, wsUrl, options = {}) {
|
|
16
|
+
super();
|
|
17
|
+
this.ws = null;
|
|
18
|
+
this._isConnected = false;
|
|
19
|
+
this._isConnecting = false;
|
|
20
|
+
this._retryCount = 0;
|
|
21
|
+
this._isDestroyed = false;
|
|
22
|
+
this._reconnectTimer = null;
|
|
23
|
+
this._pingInterval = null;
|
|
24
|
+
this._messageQueue = [];
|
|
25
|
+
this._pendingRequests = new Map();
|
|
26
|
+
/**
|
|
27
|
+
* Handle WebSocket open event.
|
|
28
|
+
*/
|
|
29
|
+
this.handleOpen = () => {
|
|
30
|
+
this._isConnecting = false;
|
|
31
|
+
this._isConnected = true;
|
|
32
|
+
this._retryCount = 0;
|
|
33
|
+
this.logger.debug('[WS] Connected');
|
|
34
|
+
this.emit('connected', undefined);
|
|
35
|
+
// Flush queued messages
|
|
36
|
+
this.flushMessageQueue();
|
|
37
|
+
// Start ping interval (every 30s)
|
|
38
|
+
this._pingInterval = setInterval(() => {
|
|
39
|
+
this.send({ type: 'ping', timestamp: nowISO() });
|
|
40
|
+
}, 30000);
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Handle WebSocket close event.
|
|
44
|
+
*/
|
|
45
|
+
this.handleClose = (event) => {
|
|
46
|
+
this._isConnected = false;
|
|
47
|
+
this._isConnecting = false;
|
|
48
|
+
this.clearPingInterval();
|
|
49
|
+
this.logger.debug('[WS] Closed:', event.code, event.reason);
|
|
50
|
+
this.emit('disconnected', { code: event.code, reason: event.reason });
|
|
51
|
+
// Auto-reconnect if enabled
|
|
52
|
+
if (this.autoReconnect && !this._isDestroyed) {
|
|
53
|
+
this.attemptReconnect();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Handle WebSocket error event.
|
|
58
|
+
*/
|
|
59
|
+
this.handleError = (event) => {
|
|
60
|
+
this.logger.error('[WS] Error:', event);
|
|
61
|
+
this.emit('error', new Error('WebSocket error occurred'));
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Handle incoming WebSocket message.
|
|
65
|
+
*/
|
|
66
|
+
this.handleMessage = (event) => {
|
|
67
|
+
try {
|
|
68
|
+
const data = JSON.parse(String(event.data));
|
|
69
|
+
// Handle pong (keep-alive response)
|
|
70
|
+
if (data.type === 'pong')
|
|
71
|
+
return;
|
|
72
|
+
// Handle errors
|
|
73
|
+
if (data.type === 'error') {
|
|
74
|
+
this.emit('error', new Error(String(data.payload ?? 'Server error')));
|
|
75
|
+
// Resolve pending request with error
|
|
76
|
+
if (data.id && this._pendingRequests.has(data.id)) {
|
|
77
|
+
const pending = this._pendingRequests.get(data.id);
|
|
78
|
+
clearTimeout(pending.timer);
|
|
79
|
+
this._pendingRequests.delete(data.id);
|
|
80
|
+
pending.reject(new Error(String(data.payload ?? 'Server error')));
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Handle message response
|
|
85
|
+
if (data.type === 'message' && data.id && this._pendingRequests.has(data.id)) {
|
|
86
|
+
const pending = this._pendingRequests.get(data.id);
|
|
87
|
+
clearTimeout(pending.timer);
|
|
88
|
+
this._pendingRequests.delete(data.id);
|
|
89
|
+
const msg = {
|
|
90
|
+
id: data.id,
|
|
91
|
+
role: 'assistant',
|
|
92
|
+
content: data.payload?.content
|
|
93
|
+
|| String(data.payload ?? ''),
|
|
94
|
+
timestamp: data.timestamp || nowISO(),
|
|
95
|
+
};
|
|
96
|
+
pending.resolve(msg);
|
|
97
|
+
this.emit('message', msg);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Handle session events
|
|
101
|
+
if (data.type === 'session') {
|
|
102
|
+
this.logger.debug('[WS] Session event:', data.payload);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Handle unsolicited messages (server push)
|
|
106
|
+
if (data.type === 'message') {
|
|
107
|
+
const msg = {
|
|
108
|
+
id: data.id || generateId('msg'),
|
|
109
|
+
role: data.payload?.role || 'assistant',
|
|
110
|
+
content: data.payload?.content || String(data.payload ?? ''),
|
|
111
|
+
timestamp: data.timestamp || nowISO(),
|
|
112
|
+
};
|
|
113
|
+
this.emit('message', msg);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
this.logger.error('[WS] Failed to parse message:', err);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
this.apiKey = apiKey;
|
|
121
|
+
this.wsUrl = wsUrl;
|
|
122
|
+
this.autoReconnect = options.autoReconnect ?? true;
|
|
123
|
+
this.maxRetries = options.maxRetries ?? 5;
|
|
124
|
+
this.initialRetryDelay = options.initialRetryDelay ?? 1000;
|
|
125
|
+
this.maxRetryDelay = options.maxRetryDelay ?? 30000;
|
|
126
|
+
this.logger = new Logger(options.debug ?? false);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Connect to the WebSocket server.
|
|
130
|
+
*/
|
|
131
|
+
async connect() {
|
|
132
|
+
if (this._isConnecting || this.isConnected)
|
|
133
|
+
return;
|
|
134
|
+
if (this._isDestroyed)
|
|
135
|
+
throw new Error('Transport is destroyed');
|
|
136
|
+
this._isConnecting = true;
|
|
137
|
+
this.logger.debug('[WS] Connecting to:', this.wsUrl);
|
|
138
|
+
try {
|
|
139
|
+
this.ws = this.createWebSocket();
|
|
140
|
+
await this.waitForConnection();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
this._isConnecting = false;
|
|
144
|
+
this.logger.error('[WS] Connection failed:', err);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Send a message through the WebSocket.
|
|
150
|
+
*/
|
|
151
|
+
async sendMessage(content, sessionId, visitorId) {
|
|
152
|
+
const envelope = {
|
|
153
|
+
type: 'message',
|
|
154
|
+
id: generateId('req'),
|
|
155
|
+
timestamp: nowISO(),
|
|
156
|
+
payload: {
|
|
157
|
+
content,
|
|
158
|
+
role: 'user',
|
|
159
|
+
session_id: sessionId,
|
|
160
|
+
visitor_id: visitorId,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
// If not connected, queue the message
|
|
165
|
+
if (!this.isConnected) {
|
|
166
|
+
this._messageQueue.push(envelope);
|
|
167
|
+
reject(new Error('WebSocket not connected. Message queued.'));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Set up response timeout (30s)
|
|
171
|
+
const timer = setTimeout(() => {
|
|
172
|
+
this._pendingRequests.delete(envelope.id);
|
|
173
|
+
reject(new Error('Response timeout'));
|
|
174
|
+
}, 30000);
|
|
175
|
+
this._pendingRequests.set(envelope.id, {
|
|
176
|
+
resolve: resolve,
|
|
177
|
+
reject,
|
|
178
|
+
timer,
|
|
179
|
+
});
|
|
180
|
+
this.send(envelope);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Disconnect from the WebSocket server.
|
|
185
|
+
*/
|
|
186
|
+
disconnect(code = 1000, reason = 'Client disconnect') {
|
|
187
|
+
this._isDestroyed = true;
|
|
188
|
+
this._isConnecting = false;
|
|
189
|
+
this.clearTimers();
|
|
190
|
+
if (this.ws) {
|
|
191
|
+
try {
|
|
192
|
+
this.ws.close(code, reason);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Already closed
|
|
196
|
+
}
|
|
197
|
+
this.ws = null;
|
|
198
|
+
}
|
|
199
|
+
this._isConnected = false;
|
|
200
|
+
this.logger.debug('[WS] Disconnected');
|
|
201
|
+
this.emit('disconnected', { code, reason });
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a WebSocket instance (handles browser vs Node.js).
|
|
205
|
+
*/
|
|
206
|
+
createWebSocket() {
|
|
207
|
+
// Build authenticated URL
|
|
208
|
+
const url = new URL(this.wsUrl);
|
|
209
|
+
url.searchParams.set('api_key', this.apiKey);
|
|
210
|
+
let ws;
|
|
211
|
+
if (typeof WebSocket !== 'undefined') {
|
|
212
|
+
// Browser WebSocket
|
|
213
|
+
ws = new WebSocket(url.toString());
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
// Node.js — try to use ws package
|
|
217
|
+
try {
|
|
218
|
+
const WS = require('ws');
|
|
219
|
+
ws = new WS(url.toString());
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
throw new Error('[WAKZ SDK] WebSocket not available. Install "ws" package for Node.js, or use HTTP transport.');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
ws.onopen = this.handleOpen;
|
|
226
|
+
ws.onclose = this.handleClose;
|
|
227
|
+
ws.onerror = this.handleError;
|
|
228
|
+
ws.onmessage = this.handleMessage;
|
|
229
|
+
return ws;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Wait for the WebSocket to open.
|
|
233
|
+
*/
|
|
234
|
+
waitForConnection() {
|
|
235
|
+
return new Promise((resolve, reject) => {
|
|
236
|
+
const timeout = setTimeout(() => {
|
|
237
|
+
reject(new Error('WebSocket connection timeout'));
|
|
238
|
+
}, 15000);
|
|
239
|
+
const ws = this.ws;
|
|
240
|
+
const onOpen = () => {
|
|
241
|
+
clearTimeout(timeout);
|
|
242
|
+
ws.removeEventListener('open', onOpen);
|
|
243
|
+
ws.removeEventListener('error', onError);
|
|
244
|
+
resolve();
|
|
245
|
+
};
|
|
246
|
+
const onError = (event) => {
|
|
247
|
+
clearTimeout(timeout);
|
|
248
|
+
ws.removeEventListener('open', onOpen);
|
|
249
|
+
ws.removeEventListener('error', onError);
|
|
250
|
+
reject(new Error('WebSocket connection error'));
|
|
251
|
+
};
|
|
252
|
+
ws.addEventListener('open', onOpen);
|
|
253
|
+
ws.addEventListener('error', onError);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Attempt to reconnect with exponential backoff.
|
|
258
|
+
*/
|
|
259
|
+
async attemptReconnect() {
|
|
260
|
+
if (this._retryCount >= this.maxRetries) {
|
|
261
|
+
this.logger.error('[WS] Max retries reached, giving up');
|
|
262
|
+
this.emit('reconnect_failed', { reason: 'Max retries exceeded' });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const delay = calculateBackoff(this._retryCount, this.initialRetryDelay, this.maxRetryDelay);
|
|
266
|
+
this._retryCount++;
|
|
267
|
+
this.logger.debug(`[WS] Reconnecting in ${Math.round(delay)}ms (attempt ${this._retryCount}/${this.maxRetries})`);
|
|
268
|
+
this.emit('reconnecting', { attempt: this._retryCount, delay });
|
|
269
|
+
await sleep(delay);
|
|
270
|
+
if (this._isDestroyed)
|
|
271
|
+
return;
|
|
272
|
+
try {
|
|
273
|
+
this._isConnecting = true;
|
|
274
|
+
this.ws = this.createWebSocket();
|
|
275
|
+
await this.waitForConnection();
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
this.logger.error('[WS] Reconnect attempt failed:', err);
|
|
279
|
+
this.attemptReconnect(); // Recursive retry
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Flush queued messages after reconnection.
|
|
284
|
+
*/
|
|
285
|
+
flushMessageQueue() {
|
|
286
|
+
while (this._messageQueue.length > 0 && this.isConnected) {
|
|
287
|
+
const envelope = this._messageQueue.shift();
|
|
288
|
+
this.send(envelope);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Send a raw envelope through the WebSocket.
|
|
293
|
+
*/
|
|
294
|
+
send(envelope) {
|
|
295
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
296
|
+
this._messageQueue.push(envelope);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
this.ws.send(JSON.stringify(envelope));
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
this.logger.error('[WS] Send error:', err);
|
|
304
|
+
this._messageQueue.push(envelope);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Perform a health check via WebSocket.
|
|
309
|
+
*/
|
|
310
|
+
async healthCheck() {
|
|
311
|
+
const startTime = Date.now();
|
|
312
|
+
try {
|
|
313
|
+
if (!this.isConnected) {
|
|
314
|
+
return { healthy: false, latency: 0 };
|
|
315
|
+
}
|
|
316
|
+
return new Promise((resolve) => {
|
|
317
|
+
const envelope = {
|
|
318
|
+
type: 'ping',
|
|
319
|
+
id: generateId('hc'),
|
|
320
|
+
timestamp: nowISO(),
|
|
321
|
+
};
|
|
322
|
+
const timer = setTimeout(() => {
|
|
323
|
+
resolve({ healthy: false, latency: Date.now() - startTime });
|
|
324
|
+
}, 5000);
|
|
325
|
+
const handler = () => {
|
|
326
|
+
clearTimeout(timer);
|
|
327
|
+
this.off('message', handler);
|
|
328
|
+
resolve({ healthy: true, latency: Date.now() - startTime });
|
|
329
|
+
};
|
|
330
|
+
this.on('message', handler);
|
|
331
|
+
this.send(envelope);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return { healthy: false, latency: Date.now() - startTime };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Clear all timers.
|
|
340
|
+
*/
|
|
341
|
+
clearTimers() {
|
|
342
|
+
this.clearPingInterval();
|
|
343
|
+
if (this._reconnectTimer) {
|
|
344
|
+
clearTimeout(this._reconnectTimer);
|
|
345
|
+
this._reconnectTimer = null;
|
|
346
|
+
}
|
|
347
|
+
// Clear pending request timeouts
|
|
348
|
+
for (const [, pending] of this._pendingRequests) {
|
|
349
|
+
clearTimeout(pending.timer);
|
|
350
|
+
}
|
|
351
|
+
this._pendingRequests.clear();
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Clear the ping interval.
|
|
355
|
+
*/
|
|
356
|
+
clearPingInterval() {
|
|
357
|
+
if (this._pingInterval) {
|
|
358
|
+
clearInterval(this._pingInterval);
|
|
359
|
+
this._pingInterval = null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=websocket.js.map
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { WAKZEventType, WAKZEventMap, WAKZEventCallback } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight typed event emitter for the WAKZ SDK.
|
|
4
|
+
* Zero external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
export declare class WAKZEventEmitter {
|
|
7
|
+
private listeners;
|
|
8
|
+
private onceListeners;
|
|
9
|
+
/**
|
|
10
|
+
* Register an event listener.
|
|
11
|
+
*/
|
|
12
|
+
on<K extends WAKZEventType>(event: K, callback: WAKZEventCallback<WAKZEventMap[K]>): this;
|
|
13
|
+
/**
|
|
14
|
+
* Register a one-time event listener (auto-removes after first call).
|
|
15
|
+
*/
|
|
16
|
+
once<K extends WAKZEventType>(event: K, callback: WAKZEventCallback<WAKZEventMap[K]>): this;
|
|
17
|
+
/**
|
|
18
|
+
* Remove a specific event listener.
|
|
19
|
+
*/
|
|
20
|
+
off<K extends WAKZEventType>(event: K, callback: WAKZEventCallback<WAKZEventMap[K]>): this;
|
|
21
|
+
/**
|
|
22
|
+
* Remove all listeners for a specific event, or all events if no event specified.
|
|
23
|
+
*/
|
|
24
|
+
removeAllListeners(event?: WAKZEventType): this;
|
|
25
|
+
/**
|
|
26
|
+
* Emit an event to all registered listeners.
|
|
27
|
+
*/
|
|
28
|
+
protected emit<K extends WAKZEventType>(event: K, data: WAKZEventMap[K]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get the count of listeners for a specific event.
|
|
31
|
+
*/
|
|
32
|
+
listenerCount(event: WAKZEventType): number;
|
|
33
|
+
/**
|
|
34
|
+
* Destroy the emitter — remove all listeners.
|
|
35
|
+
*/
|
|
36
|
+
destroy(): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAI9E;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,aAAa,CAA0B;IAE/C;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAQzF;;OAEG;IACH,IAAI,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAQ3F;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAM1F;;OAEG;IACH,kBAAkB,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAW/C;;OAEG;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IA4B9E;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM;IAI3C;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ═══════════════════════════════════════════════════════════════
|
|
3
|
+
// WAKZ SDK — Event Emitter System
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WAKZEventEmitter = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Lightweight typed event emitter for the WAKZ SDK.
|
|
9
|
+
* Zero external dependencies.
|
|
10
|
+
*/
|
|
11
|
+
class WAKZEventEmitter {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.listeners = new Map();
|
|
14
|
+
this.onceListeners = new Map();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register an event listener.
|
|
18
|
+
*/
|
|
19
|
+
on(event, callback) {
|
|
20
|
+
if (!this.listeners.has(event)) {
|
|
21
|
+
this.listeners.set(event, new Set());
|
|
22
|
+
}
|
|
23
|
+
this.listeners.get(event).add(callback);
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register a one-time event listener (auto-removes after first call).
|
|
28
|
+
*/
|
|
29
|
+
once(event, callback) {
|
|
30
|
+
if (!this.onceListeners.has(event)) {
|
|
31
|
+
this.onceListeners.set(event, new Set());
|
|
32
|
+
}
|
|
33
|
+
this.onceListeners.get(event).add(callback);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Remove a specific event listener.
|
|
38
|
+
*/
|
|
39
|
+
off(event, callback) {
|
|
40
|
+
this.listeners.get(event)?.delete(callback);
|
|
41
|
+
this.onceListeners.get(event)?.delete(callback);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Remove all listeners for a specific event, or all events if no event specified.
|
|
46
|
+
*/
|
|
47
|
+
removeAllListeners(event) {
|
|
48
|
+
if (event) {
|
|
49
|
+
this.listeners.delete(event);
|
|
50
|
+
this.onceListeners.delete(event);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.listeners.clear();
|
|
54
|
+
this.onceListeners.clear();
|
|
55
|
+
}
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Emit an event to all registered listeners.
|
|
60
|
+
*/
|
|
61
|
+
emit(event, data) {
|
|
62
|
+
// Fire persistent listeners
|
|
63
|
+
const persistent = this.listeners.get(event);
|
|
64
|
+
if (persistent) {
|
|
65
|
+
for (const cb of persistent) {
|
|
66
|
+
try {
|
|
67
|
+
cb(data);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// Prevent listener errors from breaking the emitter
|
|
71
|
+
console.error(`[WAKZ SDK] Error in "${event}" listener:`, err);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Fire and consume once-listeners
|
|
76
|
+
const once = this.onceListeners.get(event);
|
|
77
|
+
if (once) {
|
|
78
|
+
for (const cb of once) {
|
|
79
|
+
try {
|
|
80
|
+
cb(data);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.error(`[WAKZ SDK] Error in "${event}" once-listener:`, err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
this.onceListeners.delete(event);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the count of listeners for a specific event.
|
|
91
|
+
*/
|
|
92
|
+
listenerCount(event) {
|
|
93
|
+
return (this.listeners.get(event)?.size ?? 0) + (this.onceListeners.get(event)?.size ?? 0);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Destroy the emitter — remove all listeners.
|
|
97
|
+
*/
|
|
98
|
+
destroy() {
|
|
99
|
+
this.listeners.clear();
|
|
100
|
+
this.onceListeners.clear();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.WAKZEventEmitter = WAKZEventEmitter;
|
|
104
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SendMessageResponse, WidgetConfig, HealthCheckResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP/REST fallback transport for environments where WebSocket is unavailable.
|
|
4
|
+
* All requests are signed with HMAC-SHA256 for secure authentication.
|
|
5
|
+
*/
|
|
6
|
+
export declare class HttpTransport {
|
|
7
|
+
private baseUrl;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private timeout;
|
|
10
|
+
private logger;
|
|
11
|
+
constructor(apiKey: string, baseUrl: string, timeout?: number, debug?: boolean);
|
|
12
|
+
/**
|
|
13
|
+
* Send a chat message via REST API.
|
|
14
|
+
*/
|
|
15
|
+
sendMessage(content: string, sessionId?: string, visitorId?: string): Promise<SendMessageResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* Fetch widget configuration.
|
|
18
|
+
*/
|
|
19
|
+
fetchWidgetConfig(): Promise<WidgetConfig | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Perform a health check against the API.
|
|
22
|
+
*/
|
|
23
|
+
healthCheck(): Promise<HealthCheckResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Get the current session from the server.
|
|
26
|
+
*/
|
|
27
|
+
getSession(visitorId: string): Promise<{
|
|
28
|
+
id: string;
|
|
29
|
+
messageCount: number;
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
} | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch with timeout support.
|
|
34
|
+
*/
|
|
35
|
+
private fetchWithTimeout;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EAEnB,YAAY,EACZ,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAIjB;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAGrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAc,EACvB,KAAK,GAAE,OAAe;IAQxB;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC;IAiD/B;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAuBvD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IA2B/C;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,EAAE,EAAE,MAAM,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,OAAO,CAAC;KACnB,GAAG,IAAI,CAAC;IAkBT;;OAEG;YACW,gBAAgB;CAyB/B"}
|