@pocketping/sdk-node 0.1.0 → 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 +305 -0
- package/dist/index.cjs +884 -0
- package/dist/index.d.cts +421 -0
- package/dist/index.d.ts +202 -3
- package/dist/index.js +408 -48
- package/package.json +33 -5
- package/dist/index.d.mts +0 -222
- package/dist/index.mjs +0 -468
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Storage adapter interface.
|
|
5
|
+
* Implement this interface to use any database with PocketPing.
|
|
6
|
+
*/
|
|
7
|
+
interface Storage {
|
|
8
|
+
createSession(session: Session): Promise<void>;
|
|
9
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
10
|
+
getSessionByVisitorId?(visitorId: string): Promise<Session | null>;
|
|
11
|
+
updateSession(session: Session): Promise<void>;
|
|
12
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
13
|
+
saveMessage(message: Message): Promise<void>;
|
|
14
|
+
getMessages(sessionId: string, after?: string, limit?: number): Promise<Message[]>;
|
|
15
|
+
getMessage(messageId: string): Promise<Message | null>;
|
|
16
|
+
cleanupOldSessions?(olderThan: Date): Promise<number>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Bridge interface for notification channels.
|
|
21
|
+
* Implement this interface to add support for Telegram, Discord, Slack, etc.
|
|
22
|
+
*/
|
|
23
|
+
interface Bridge {
|
|
24
|
+
/** Unique name for this bridge */
|
|
25
|
+
name: string;
|
|
26
|
+
/** Called when the bridge is added to PocketPing */
|
|
27
|
+
init?(pocketping: PocketPing): void | Promise<void>;
|
|
28
|
+
/** Called when a new chat session is created */
|
|
29
|
+
onNewSession?(session: Session): void | Promise<void>;
|
|
30
|
+
/** Called when a visitor sends a message */
|
|
31
|
+
onVisitorMessage?(message: Message, session: Session): void | Promise<void>;
|
|
32
|
+
/** Called when an operator sends a message (for cross-bridge sync) */
|
|
33
|
+
onOperatorMessage?(message: Message, session: Session, sourceBridge?: string, operatorName?: string): void | Promise<void>;
|
|
34
|
+
/** Called when visitor starts/stops typing */
|
|
35
|
+
onTyping?(sessionId: string, isTyping: boolean): void | Promise<void>;
|
|
36
|
+
/** Called when messages are marked as delivered/read */
|
|
37
|
+
onMessageRead?(sessionId: string, messageIds: string[], status: MessageStatus, session: Session): void | Promise<void>;
|
|
38
|
+
/** Called when a custom event is triggered from the widget */
|
|
39
|
+
onCustomEvent?(event: CustomEvent, session: Session): void | Promise<void>;
|
|
40
|
+
/** Called when a user identifies themselves via PocketPing.identify() */
|
|
41
|
+
onIdentityUpdate?(session: Session): void | Promise<void>;
|
|
42
|
+
/** Cleanup when bridge is removed */
|
|
43
|
+
destroy?(): void | Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* AI provider interface.
|
|
48
|
+
* Implement this to add support for OpenAI, Gemini, Claude, or local models.
|
|
49
|
+
*/
|
|
50
|
+
interface AIProvider {
|
|
51
|
+
/** Provider name */
|
|
52
|
+
name: string;
|
|
53
|
+
/** Generate a response to the conversation */
|
|
54
|
+
generateResponse(messages: Message[], systemPrompt?: string): Promise<string>;
|
|
55
|
+
/** Check if the provider is available */
|
|
56
|
+
isAvailable(): Promise<boolean>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface PocketPingConfig {
|
|
60
|
+
/** Storage adapter for sessions and messages */
|
|
61
|
+
storage?: Storage | 'memory';
|
|
62
|
+
/** Notification bridges (Telegram, Discord, etc.) */
|
|
63
|
+
bridges?: Bridge[];
|
|
64
|
+
/** AI fallback configuration */
|
|
65
|
+
ai?: AIConfig;
|
|
66
|
+
/** Welcome message shown to new visitors */
|
|
67
|
+
welcomeMessage?: string;
|
|
68
|
+
/** Seconds of inactivity before AI takes over (default: 300) */
|
|
69
|
+
aiTakeoverDelay?: number;
|
|
70
|
+
/** Callback when a new session is created */
|
|
71
|
+
onNewSession?: (session: Session) => void | Promise<void>;
|
|
72
|
+
/** Callback when a message is received */
|
|
73
|
+
onMessage?: (message: Message, session: Session) => void | Promise<void>;
|
|
74
|
+
/** Callback when a custom event is received from widget */
|
|
75
|
+
onEvent?: (event: CustomEvent, session: Session) => void | Promise<void>;
|
|
76
|
+
/** Callback when a user identifies themselves */
|
|
77
|
+
onIdentify?: (session: Session) => void | Promise<void>;
|
|
78
|
+
/** Webhook URL to forward custom events (Zapier, Make, n8n, etc.) */
|
|
79
|
+
webhookUrl?: string;
|
|
80
|
+
/** Secret key for HMAC-SHA256 signature (X-PocketPing-Signature header) */
|
|
81
|
+
webhookSecret?: string;
|
|
82
|
+
/** Webhook request timeout in milliseconds (default: 5000) */
|
|
83
|
+
webhookTimeout?: number;
|
|
84
|
+
/** Minimum supported widget version (e.g., "0.2.0") */
|
|
85
|
+
minWidgetVersion?: string;
|
|
86
|
+
/** Latest available widget version (e.g., "0.3.0") */
|
|
87
|
+
latestWidgetVersion?: string;
|
|
88
|
+
/** Custom message for version warnings */
|
|
89
|
+
versionWarningMessage?: string;
|
|
90
|
+
/** URL to upgrade instructions */
|
|
91
|
+
versionUpgradeUrl?: string;
|
|
92
|
+
}
|
|
93
|
+
interface AIConfig {
|
|
94
|
+
provider: AIProvider | 'openai' | 'gemini' | 'anthropic';
|
|
95
|
+
apiKey?: string;
|
|
96
|
+
model?: string;
|
|
97
|
+
systemPrompt?: string;
|
|
98
|
+
fallbackAfter?: number;
|
|
99
|
+
}
|
|
100
|
+
/** User identity data from PocketPing.identify() */
|
|
101
|
+
interface UserIdentity {
|
|
102
|
+
/** Required unique user identifier */
|
|
103
|
+
id: string;
|
|
104
|
+
/** User's email address */
|
|
105
|
+
email?: string;
|
|
106
|
+
/** User's display name */
|
|
107
|
+
name?: string;
|
|
108
|
+
/** Any custom fields (plan, company, etc.) */
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
interface Session {
|
|
112
|
+
id: string;
|
|
113
|
+
visitorId: string;
|
|
114
|
+
createdAt: Date;
|
|
115
|
+
lastActivity: Date;
|
|
116
|
+
operatorOnline: boolean;
|
|
117
|
+
aiActive: boolean;
|
|
118
|
+
metadata?: SessionMetadata;
|
|
119
|
+
/** User identity if identified via PocketPing.identify() */
|
|
120
|
+
identity?: UserIdentity;
|
|
121
|
+
}
|
|
122
|
+
interface SessionMetadata {
|
|
123
|
+
url?: string;
|
|
124
|
+
referrer?: string;
|
|
125
|
+
pageTitle?: string;
|
|
126
|
+
userAgent?: string;
|
|
127
|
+
timezone?: string;
|
|
128
|
+
language?: string;
|
|
129
|
+
screenResolution?: string;
|
|
130
|
+
ip?: string;
|
|
131
|
+
country?: string;
|
|
132
|
+
city?: string;
|
|
133
|
+
deviceType?: 'desktop' | 'mobile' | 'tablet';
|
|
134
|
+
browser?: string;
|
|
135
|
+
os?: string;
|
|
136
|
+
[key: string]: unknown;
|
|
137
|
+
}
|
|
138
|
+
type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read';
|
|
139
|
+
interface Message {
|
|
140
|
+
id: string;
|
|
141
|
+
sessionId: string;
|
|
142
|
+
content: string;
|
|
143
|
+
sender: 'visitor' | 'operator' | 'ai';
|
|
144
|
+
timestamp: Date;
|
|
145
|
+
replyTo?: string;
|
|
146
|
+
metadata?: Record<string, unknown>;
|
|
147
|
+
status?: MessageStatus;
|
|
148
|
+
deliveredAt?: Date;
|
|
149
|
+
readAt?: Date;
|
|
150
|
+
}
|
|
151
|
+
interface ConnectRequest {
|
|
152
|
+
visitorId: string;
|
|
153
|
+
sessionId?: string;
|
|
154
|
+
metadata?: SessionMetadata;
|
|
155
|
+
/** User identity if already identified */
|
|
156
|
+
identity?: UserIdentity;
|
|
157
|
+
}
|
|
158
|
+
/** Tracked element configuration (for SaaS auto-tracking) */
|
|
159
|
+
interface TrackedElement {
|
|
160
|
+
/** CSS selector for the element(s) to track */
|
|
161
|
+
selector: string;
|
|
162
|
+
/** DOM event to listen for (default: 'click') */
|
|
163
|
+
event?: 'click' | 'submit' | 'focus' | 'change' | 'mouseenter';
|
|
164
|
+
/** Event name sent to backend */
|
|
165
|
+
name: string;
|
|
166
|
+
/** If provided, opens widget with this message when triggered */
|
|
167
|
+
widgetMessage?: string;
|
|
168
|
+
/** Additional data to send with the event */
|
|
169
|
+
data?: Record<string, unknown>;
|
|
170
|
+
}
|
|
171
|
+
/** Options for trigger() method */
|
|
172
|
+
interface TriggerOptions {
|
|
173
|
+
/** If provided, opens the widget and shows this message */
|
|
174
|
+
widgetMessage?: string;
|
|
175
|
+
}
|
|
176
|
+
interface ConnectResponse {
|
|
177
|
+
sessionId: string;
|
|
178
|
+
visitorId: string;
|
|
179
|
+
operatorOnline: boolean;
|
|
180
|
+
welcomeMessage?: string;
|
|
181
|
+
messages: Message[];
|
|
182
|
+
/** Tracked elements configuration (for SaaS auto-tracking) */
|
|
183
|
+
trackedElements?: TrackedElement[];
|
|
184
|
+
}
|
|
185
|
+
interface SendMessageRequest {
|
|
186
|
+
sessionId: string;
|
|
187
|
+
content: string;
|
|
188
|
+
sender: 'visitor' | 'operator';
|
|
189
|
+
replyTo?: string;
|
|
190
|
+
}
|
|
191
|
+
interface SendMessageResponse {
|
|
192
|
+
messageId: string;
|
|
193
|
+
timestamp: string;
|
|
194
|
+
}
|
|
195
|
+
interface GetMessagesRequest {
|
|
196
|
+
sessionId: string;
|
|
197
|
+
after?: string;
|
|
198
|
+
limit?: number;
|
|
199
|
+
}
|
|
200
|
+
interface GetMessagesResponse {
|
|
201
|
+
messages: Message[];
|
|
202
|
+
hasMore: boolean;
|
|
203
|
+
}
|
|
204
|
+
interface TypingRequest {
|
|
205
|
+
sessionId: string;
|
|
206
|
+
sender: 'visitor' | 'operator';
|
|
207
|
+
isTyping?: boolean;
|
|
208
|
+
}
|
|
209
|
+
interface ReadRequest {
|
|
210
|
+
sessionId: string;
|
|
211
|
+
messageIds: string[];
|
|
212
|
+
status?: MessageStatus;
|
|
213
|
+
}
|
|
214
|
+
interface ReadResponse {
|
|
215
|
+
updated: number;
|
|
216
|
+
}
|
|
217
|
+
interface IdentifyRequest {
|
|
218
|
+
sessionId: string;
|
|
219
|
+
identity: UserIdentity;
|
|
220
|
+
}
|
|
221
|
+
interface IdentifyResponse {
|
|
222
|
+
ok: boolean;
|
|
223
|
+
}
|
|
224
|
+
interface PresenceResponse {
|
|
225
|
+
online: boolean;
|
|
226
|
+
operators?: Array<{
|
|
227
|
+
id: string;
|
|
228
|
+
name: string;
|
|
229
|
+
avatar?: string;
|
|
230
|
+
}>;
|
|
231
|
+
aiEnabled: boolean;
|
|
232
|
+
aiActiveAfter?: number;
|
|
233
|
+
}
|
|
234
|
+
/** Custom event sent from widget to backend or vice versa */
|
|
235
|
+
interface CustomEvent {
|
|
236
|
+
/** Event name (e.g., 'clicked_pricing', 'show_offer') */
|
|
237
|
+
name: string;
|
|
238
|
+
/** Event payload */
|
|
239
|
+
data?: Record<string, unknown>;
|
|
240
|
+
/** Timestamp of the event */
|
|
241
|
+
timestamp: string;
|
|
242
|
+
/** Session ID (populated by SDK when event comes from widget) */
|
|
243
|
+
sessionId?: string;
|
|
244
|
+
}
|
|
245
|
+
/** Handler for custom events */
|
|
246
|
+
type CustomEventHandler = (event: CustomEvent, session: Session) => void | Promise<void>;
|
|
247
|
+
type VersionStatus = 'ok' | 'outdated' | 'deprecated' | 'unsupported';
|
|
248
|
+
interface VersionCheckResult {
|
|
249
|
+
status: VersionStatus;
|
|
250
|
+
message?: string;
|
|
251
|
+
minVersion?: string;
|
|
252
|
+
latestVersion?: string;
|
|
253
|
+
canContinue: boolean;
|
|
254
|
+
}
|
|
255
|
+
/** Payload sent to webhook URL */
|
|
256
|
+
interface WebhookPayload {
|
|
257
|
+
/** The custom event */
|
|
258
|
+
event: CustomEvent;
|
|
259
|
+
/** Session information */
|
|
260
|
+
session: {
|
|
261
|
+
id: string;
|
|
262
|
+
visitorId: string;
|
|
263
|
+
metadata?: SessionMetadata;
|
|
264
|
+
identity?: UserIdentity;
|
|
265
|
+
};
|
|
266
|
+
/** Timestamp when webhook was sent */
|
|
267
|
+
sentAt: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
declare class PocketPing {
|
|
271
|
+
private storage;
|
|
272
|
+
private bridges;
|
|
273
|
+
private config;
|
|
274
|
+
private wss;
|
|
275
|
+
private sessionSockets;
|
|
276
|
+
private operatorOnline;
|
|
277
|
+
private eventHandlers;
|
|
278
|
+
constructor(config?: PocketPingConfig);
|
|
279
|
+
private initStorage;
|
|
280
|
+
middleware(): (req: IncomingMessage & {
|
|
281
|
+
body?: unknown;
|
|
282
|
+
query?: Record<string, string>;
|
|
283
|
+
}, res: ServerResponse, next?: () => void) => void;
|
|
284
|
+
private parseBody;
|
|
285
|
+
attachWebSocket(server: any): void;
|
|
286
|
+
private handleWebSocketMessage;
|
|
287
|
+
private handleCustomEvent;
|
|
288
|
+
private broadcastToSession;
|
|
289
|
+
handleConnect(request: ConnectRequest): Promise<ConnectResponse>;
|
|
290
|
+
handleMessage(request: SendMessageRequest): Promise<SendMessageResponse>;
|
|
291
|
+
handleGetMessages(request: GetMessagesRequest): Promise<GetMessagesResponse>;
|
|
292
|
+
handleTyping(request: TypingRequest): Promise<{
|
|
293
|
+
ok: boolean;
|
|
294
|
+
}>;
|
|
295
|
+
handlePresence(): Promise<PresenceResponse>;
|
|
296
|
+
handleRead(request: ReadRequest): Promise<ReadResponse>;
|
|
297
|
+
/**
|
|
298
|
+
* Handle user identification from widget
|
|
299
|
+
* Called when visitor calls PocketPing.identify()
|
|
300
|
+
*/
|
|
301
|
+
handleIdentify(request: IdentifyRequest): Promise<IdentifyResponse>;
|
|
302
|
+
/**
|
|
303
|
+
* Get a session by ID
|
|
304
|
+
*/
|
|
305
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
306
|
+
sendOperatorMessage(sessionId: string, content: string): Promise<Message>;
|
|
307
|
+
setOperatorOnline(online: boolean): void;
|
|
308
|
+
/**
|
|
309
|
+
* Subscribe to custom events from widgets
|
|
310
|
+
* @param eventName - The name of the event to listen for, or '*' for all events
|
|
311
|
+
* @param handler - Callback function when event is received
|
|
312
|
+
* @returns Unsubscribe function
|
|
313
|
+
* @example
|
|
314
|
+
* // Listen for specific event
|
|
315
|
+
* pp.onEvent('clicked_pricing', async (event, session) => {
|
|
316
|
+
* console.log(`User ${session.visitorId} clicked pricing: ${event.data?.plan}`)
|
|
317
|
+
* })
|
|
318
|
+
*
|
|
319
|
+
* // Listen for all events
|
|
320
|
+
* pp.onEvent('*', async (event, session) => {
|
|
321
|
+
* console.log(`Event: ${event.name}`, event.data)
|
|
322
|
+
* })
|
|
323
|
+
*/
|
|
324
|
+
onEvent(eventName: string, handler: CustomEventHandler): () => void;
|
|
325
|
+
/**
|
|
326
|
+
* Unsubscribe from a custom event
|
|
327
|
+
* @param eventName - The name of the event
|
|
328
|
+
* @param handler - The handler to remove
|
|
329
|
+
*/
|
|
330
|
+
offEvent(eventName: string, handler: CustomEventHandler): void;
|
|
331
|
+
/**
|
|
332
|
+
* Send a custom event to a specific widget/session
|
|
333
|
+
* @param sessionId - The session ID to send the event to
|
|
334
|
+
* @param eventName - The name of the event
|
|
335
|
+
* @param data - Optional payload to send with the event
|
|
336
|
+
* @example
|
|
337
|
+
* // Send a promotion offer to a specific user
|
|
338
|
+
* pp.emitEvent('session-123', 'show_offer', {
|
|
339
|
+
* discount: 20,
|
|
340
|
+
* code: 'SAVE20',
|
|
341
|
+
* message: 'Special offer just for you!'
|
|
342
|
+
* })
|
|
343
|
+
*/
|
|
344
|
+
emitEvent(sessionId: string, eventName: string, data?: Record<string, unknown>): void;
|
|
345
|
+
/**
|
|
346
|
+
* Broadcast a custom event to all connected widgets
|
|
347
|
+
* @param eventName - The name of the event
|
|
348
|
+
* @param data - Optional payload to send with the event
|
|
349
|
+
* @example
|
|
350
|
+
* // Notify all users about maintenance
|
|
351
|
+
* pp.broadcastEvent('maintenance_warning', {
|
|
352
|
+
* message: 'Site will be down for maintenance in 5 minutes'
|
|
353
|
+
* })
|
|
354
|
+
*/
|
|
355
|
+
broadcastEvent(eventName: string, data?: Record<string, unknown>): void;
|
|
356
|
+
/**
|
|
357
|
+
* Process a custom event server-side (runs handlers, bridges, webhooks)
|
|
358
|
+
* Useful for server-side automation or triggering events programmatically
|
|
359
|
+
* @param sessionId - The session ID to associate with the event
|
|
360
|
+
* @param eventName - The name of the event
|
|
361
|
+
* @param data - Optional payload for the event
|
|
362
|
+
* @example
|
|
363
|
+
* // Trigger event from backend logic (e.g., after purchase)
|
|
364
|
+
* await pp.triggerEvent('session-123', 'purchase_completed', {
|
|
365
|
+
* orderId: 'order-456',
|
|
366
|
+
* amount: 99.99
|
|
367
|
+
* })
|
|
368
|
+
*/
|
|
369
|
+
triggerEvent(sessionId: string, eventName: string, data?: Record<string, unknown>): Promise<void>;
|
|
370
|
+
private notifyBridges;
|
|
371
|
+
private notifyBridgesRead;
|
|
372
|
+
private notifyBridgesEvent;
|
|
373
|
+
private notifyBridgesIdentity;
|
|
374
|
+
/**
|
|
375
|
+
* Forward custom event to configured webhook URL (non-blocking)
|
|
376
|
+
* Used for integrations with Zapier, Make, n8n, or custom backends
|
|
377
|
+
*/
|
|
378
|
+
private forwardToWebhook;
|
|
379
|
+
/**
|
|
380
|
+
* Forward identity update to webhook as a special event
|
|
381
|
+
*/
|
|
382
|
+
private forwardIdentityToWebhook;
|
|
383
|
+
addBridge(bridge: Bridge): void;
|
|
384
|
+
private generateId;
|
|
385
|
+
getStorage(): Storage;
|
|
386
|
+
/**
|
|
387
|
+
* Check widget version against configured min/latest versions
|
|
388
|
+
* @param widgetVersion - Version from X-PocketPing-Version header
|
|
389
|
+
* @returns Version check result with status and headers to set
|
|
390
|
+
*/
|
|
391
|
+
checkWidgetVersion(widgetVersion: string | undefined): VersionCheckResult;
|
|
392
|
+
/**
|
|
393
|
+
* Set version warning headers on HTTP response
|
|
394
|
+
*/
|
|
395
|
+
private setVersionHeaders;
|
|
396
|
+
/**
|
|
397
|
+
* Send version warning via WebSocket to a session
|
|
398
|
+
*/
|
|
399
|
+
sendVersionWarning(sessionId: string, versionCheck: VersionCheckResult): void;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* In-memory storage adapter.
|
|
404
|
+
* Useful for development and testing. Data is lost on restart.
|
|
405
|
+
*/
|
|
406
|
+
declare class MemoryStorage implements Storage {
|
|
407
|
+
private sessions;
|
|
408
|
+
private messages;
|
|
409
|
+
private messageById;
|
|
410
|
+
createSession(session: Session): Promise<void>;
|
|
411
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
412
|
+
getSessionByVisitorId(visitorId: string): Promise<Session | null>;
|
|
413
|
+
updateSession(session: Session): Promise<void>;
|
|
414
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
415
|
+
saveMessage(message: Message): Promise<void>;
|
|
416
|
+
getMessages(sessionId: string, after?: string, limit?: number): Promise<Message[]>;
|
|
417
|
+
getMessage(messageId: string): Promise<Message | null>;
|
|
418
|
+
cleanupOldSessions(olderThan: Date): Promise<number>;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export { type AIProvider, type Bridge, type ConnectRequest, type ConnectResponse, type CustomEvent, type CustomEventHandler, MemoryStorage, type Message, PocketPing, type PocketPingConfig, type PresenceResponse, type SendMessageRequest, type SendMessageResponse, type Session, type Storage, type TrackedElement, type TriggerOptions, type WebhookPayload };
|