@pocketping/sdk-node 0.2.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.mjs → index.cjs} +40 -12
- package/dist/{index.d.mts → index.d.cts} +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +12 -40
- package/package.json +29 -4
package/README.md
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# PocketPing Node.js SDK
|
|
2
|
+
|
|
3
|
+
Node.js SDK for PocketPing - real-time customer chat with mobile notifications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @pocketping/sdk-node
|
|
9
|
+
|
|
10
|
+
# Or with pnpm
|
|
11
|
+
pnpm add @pocketping/sdk-node
|
|
12
|
+
|
|
13
|
+
# Or with yarn
|
|
14
|
+
yarn add @pocketping/sdk-node
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start with Express
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import express from 'express';
|
|
21
|
+
import { createServer } from 'http';
|
|
22
|
+
import { PocketPing } from '@pocketping/sdk-node';
|
|
23
|
+
|
|
24
|
+
const app = express();
|
|
25
|
+
const server = createServer(app);
|
|
26
|
+
|
|
27
|
+
app.use(express.json());
|
|
28
|
+
|
|
29
|
+
// Initialize PocketPing
|
|
30
|
+
const pp = new PocketPing({
|
|
31
|
+
welcomeMessage: 'Hi! How can we help you today?',
|
|
32
|
+
onNewSession: (session) => {
|
|
33
|
+
console.log(`New session: ${session.id}`);
|
|
34
|
+
},
|
|
35
|
+
onMessage: (message, session) => {
|
|
36
|
+
console.log(`Message from ${message.sender}: ${message.content}`);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Mount PocketPing routes
|
|
41
|
+
app.use('/pocketping', pp.middleware());
|
|
42
|
+
|
|
43
|
+
// Attach WebSocket for real-time communication
|
|
44
|
+
pp.attachWebSocket(server);
|
|
45
|
+
|
|
46
|
+
server.listen(3000, () => {
|
|
47
|
+
console.log('Server running on http://localhost:3000');
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configuration Options
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const pp = new PocketPing({
|
|
55
|
+
// Welcome message shown to new visitors
|
|
56
|
+
welcomeMessage: 'Hi! How can we help you?',
|
|
57
|
+
|
|
58
|
+
// Callbacks
|
|
59
|
+
onNewSession: (session) => { /* ... */ },
|
|
60
|
+
onMessage: (message, session) => { /* ... */ },
|
|
61
|
+
onEvent: (event, session) => { /* ... */ },
|
|
62
|
+
|
|
63
|
+
// Custom storage (default: in-memory)
|
|
64
|
+
storage: new MemoryStorage(),
|
|
65
|
+
|
|
66
|
+
// Bridge server for notifications (Telegram, Discord, Slack)
|
|
67
|
+
bridgeServerUrl: 'http://localhost:3001',
|
|
68
|
+
|
|
69
|
+
// Protocol version settings
|
|
70
|
+
protocolVersion: '1.0',
|
|
71
|
+
minSupportedVersion: '0.1',
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Architecture Options
|
|
76
|
+
|
|
77
|
+
### 1. Embedded Mode (Simple)
|
|
78
|
+
|
|
79
|
+
SDK handles everything directly - best for single server deployments:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { PocketPing } from '@pocketping/sdk-node';
|
|
83
|
+
|
|
84
|
+
const pp = new PocketPing({
|
|
85
|
+
welcomeMessage: 'Hello!',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
app.use('/pocketping', pp.middleware());
|
|
89
|
+
pp.attachWebSocket(server);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Bridge Server Mode (Recommended)
|
|
93
|
+
|
|
94
|
+
SDK connects to a dedicated bridge server for notifications:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const pp = new PocketPing({
|
|
98
|
+
welcomeMessage: 'Hello!',
|
|
99
|
+
bridgeServerUrl: process.env.BRIDGE_SERVER_URL,
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The bridge server handles Telegram, Discord, and Slack integrations, keeping your main server lightweight.
|
|
104
|
+
|
|
105
|
+
## Custom Storage
|
|
106
|
+
|
|
107
|
+
Implement the `Storage` interface for persistence:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { Storage, Session, Message } from '@pocketping/sdk-node';
|
|
111
|
+
|
|
112
|
+
class PostgresStorage implements Storage {
|
|
113
|
+
async createSession(session: Session): Promise<void> {
|
|
114
|
+
// Your implementation
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async getSession(sessionId: string): Promise<Session | null> {
|
|
118
|
+
// Your implementation
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async saveMessage(message: Message): Promise<void> {
|
|
122
|
+
// Your implementation
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async getMessages(sessionId: string, options?: { after?: string; limit?: number }): Promise<Message[]> {
|
|
126
|
+
// Your implementation
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ... implement other methods
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const pp = new PocketPing({
|
|
133
|
+
storage: new PostgresStorage(),
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Events / Callbacks
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const pp = new PocketPing({
|
|
141
|
+
onNewSession: (session) => {
|
|
142
|
+
console.log(`New session: ${session.id}`);
|
|
143
|
+
// Notify your team, log to analytics, etc.
|
|
144
|
+
},
|
|
145
|
+
onMessage: (message, session) => {
|
|
146
|
+
console.log(`Message from ${message.sender}: ${message.content}`);
|
|
147
|
+
},
|
|
148
|
+
onEvent: (event, session) => {
|
|
149
|
+
console.log(`Custom event: ${event.name}`, event.data);
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Custom Events
|
|
155
|
+
|
|
156
|
+
PocketPing supports bidirectional custom events between your website and backend.
|
|
157
|
+
|
|
158
|
+
### Listening for Events (Widget -> Backend)
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// Using callback in config
|
|
162
|
+
const pp = new PocketPing({
|
|
163
|
+
onEvent: (event, session) => {
|
|
164
|
+
console.log(`Event ${event.name} from session ${session.id}`);
|
|
165
|
+
console.log(`Data:`, event.data);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Or using subscription
|
|
170
|
+
pp.onEvent('clicked_pricing', (event, session) => {
|
|
171
|
+
console.log(`User interested in: ${event.data?.plan}`);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Subscribe to all events
|
|
175
|
+
pp.onEvent('*', (event, session) => {
|
|
176
|
+
console.log(`Event: ${event.name}`, event.data);
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Sending Events (Backend -> Widget)
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Send to a specific session
|
|
184
|
+
await pp.emitEvent('session-123', 'show_offer', {
|
|
185
|
+
discount: 20,
|
|
186
|
+
code: 'SAVE20',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Broadcast to all connected sessions
|
|
190
|
+
await pp.broadcastEvent('announcement', {
|
|
191
|
+
message: 'New feature launched!',
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## User Identification
|
|
196
|
+
|
|
197
|
+
Track and identify users across sessions:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// On the frontend (widget)
|
|
201
|
+
PocketPing.identify({
|
|
202
|
+
userId: 'user_123',
|
|
203
|
+
email: 'john@example.com',
|
|
204
|
+
name: 'John Doe',
|
|
205
|
+
plan: 'pro',
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Get current identity
|
|
209
|
+
const identity = PocketPing.getIdentity();
|
|
210
|
+
|
|
211
|
+
// Reset identity (e.g., on logout)
|
|
212
|
+
PocketPing.reset();
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
User identity is automatically included in session metadata and forwarded to bridges.
|
|
216
|
+
|
|
217
|
+
## Operator Presence
|
|
218
|
+
|
|
219
|
+
Control operator online status:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// Set operator as online
|
|
223
|
+
pp.setOperatorOnline(true);
|
|
224
|
+
|
|
225
|
+
// Set operator as offline
|
|
226
|
+
pp.setOperatorOnline(false);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
When using the bridge server, presence is managed automatically via Telegram/Discord/Slack commands.
|
|
230
|
+
|
|
231
|
+
## API Reference
|
|
232
|
+
|
|
233
|
+
### PocketPing Class
|
|
234
|
+
|
|
235
|
+
| Method | Description |
|
|
236
|
+
|--------|-------------|
|
|
237
|
+
| `middleware()` | Returns Express middleware for HTTP routes |
|
|
238
|
+
| `attachWebSocket(server)` | Attaches WebSocket handler for real-time communication |
|
|
239
|
+
| `setOperatorOnline(online)` | Sets operator online/offline status |
|
|
240
|
+
| `onEvent(name, callback)` | Subscribe to custom events |
|
|
241
|
+
| `offEvent(name, callback)` | Unsubscribe from custom events |
|
|
242
|
+
| `emitEvent(sessionId, name, data)` | Send event to specific session |
|
|
243
|
+
| `broadcastEvent(name, data)` | Broadcast event to all sessions |
|
|
244
|
+
| `getSession(sessionId)` | Get session by ID |
|
|
245
|
+
| `getMessages(sessionId, options)` | Get messages for a session |
|
|
246
|
+
|
|
247
|
+
### Types
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
interface Session {
|
|
251
|
+
id: string;
|
|
252
|
+
visitorId: string;
|
|
253
|
+
metadata: SessionMetadata;
|
|
254
|
+
createdAt: Date;
|
|
255
|
+
lastActivity: Date;
|
|
256
|
+
status: 'active' | 'closed';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
interface Message {
|
|
260
|
+
id: string;
|
|
261
|
+
sessionId: string;
|
|
262
|
+
sender: 'visitor' | 'operator' | 'system' | 'ai';
|
|
263
|
+
content: string;
|
|
264
|
+
timestamp: Date;
|
|
265
|
+
metadata?: Record<string, unknown>;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
interface CustomEvent {
|
|
269
|
+
name: string;
|
|
270
|
+
data?: Record<string, unknown>;
|
|
271
|
+
timestamp: Date;
|
|
272
|
+
sessionId?: string;
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Widget Integration
|
|
277
|
+
|
|
278
|
+
Add the widget to your website:
|
|
279
|
+
|
|
280
|
+
```html
|
|
281
|
+
<script src="https://unpkg.com/@pocketping/widget"></script>
|
|
282
|
+
<script>
|
|
283
|
+
PocketPing.init({
|
|
284
|
+
endpoint: '/pocketping',
|
|
285
|
+
theme: 'light', // or 'dark'
|
|
286
|
+
primaryColor: '#667eea',
|
|
287
|
+
});
|
|
288
|
+
</script>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Or via npm:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { init } from '@pocketping/widget';
|
|
295
|
+
|
|
296
|
+
init({
|
|
297
|
+
endpoint: '/pocketping',
|
|
298
|
+
theme: 'dark',
|
|
299
|
+
primaryColor: '#667eea',
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT
|
|
@@ -1,6 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
MemoryStorage: () => MemoryStorage,
|
|
24
|
+
PocketPing: () => PocketPing
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
1
28
|
// src/pocketping.ts
|
|
2
|
-
|
|
3
|
-
|
|
29
|
+
var import_crypto = require("crypto");
|
|
30
|
+
var import_ws = require("ws");
|
|
4
31
|
|
|
5
32
|
// src/storage/memory.ts
|
|
6
33
|
var MemoryStorage = class {
|
|
@@ -256,7 +283,7 @@ var PocketPing = class {
|
|
|
256
283
|
// ─────────────────────────────────────────────────────────────────
|
|
257
284
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
258
285
|
attachWebSocket(server) {
|
|
259
|
-
this.wss = new WebSocketServer({
|
|
286
|
+
this.wss = new import_ws.WebSocketServer({
|
|
260
287
|
server,
|
|
261
288
|
path: "/pocketping/stream"
|
|
262
289
|
});
|
|
@@ -334,7 +361,7 @@ var PocketPing = class {
|
|
|
334
361
|
if (!sockets) return;
|
|
335
362
|
const message = JSON.stringify(event);
|
|
336
363
|
for (const ws of sockets) {
|
|
337
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
364
|
+
if (ws.readyState === import_ws.WebSocket.OPEN) {
|
|
338
365
|
ws.send(message);
|
|
339
366
|
}
|
|
340
367
|
}
|
|
@@ -479,7 +506,7 @@ var PocketPing = class {
|
|
|
479
506
|
readAt: status === "read" ? now.toISOString() : void 0
|
|
480
507
|
}
|
|
481
508
|
});
|
|
482
|
-
await this.notifyBridgesRead(request.sessionId, request.messageIds, status);
|
|
509
|
+
await this.notifyBridgesRead(request.sessionId, request.messageIds, status, session);
|
|
483
510
|
return { updated };
|
|
484
511
|
}
|
|
485
512
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -656,7 +683,7 @@ var PocketPing = class {
|
|
|
656
683
|
await bridge.onNewSession?.(args[0]);
|
|
657
684
|
break;
|
|
658
685
|
case "message":
|
|
659
|
-
await bridge.
|
|
686
|
+
await bridge.onVisitorMessage?.(args[0], args[1]);
|
|
660
687
|
break;
|
|
661
688
|
}
|
|
662
689
|
} catch (err) {
|
|
@@ -664,10 +691,10 @@ var PocketPing = class {
|
|
|
664
691
|
}
|
|
665
692
|
}
|
|
666
693
|
}
|
|
667
|
-
async notifyBridgesRead(sessionId, messageIds, status) {
|
|
694
|
+
async notifyBridgesRead(sessionId, messageIds, status, session) {
|
|
668
695
|
for (const bridge of this.bridges) {
|
|
669
696
|
try {
|
|
670
|
-
await bridge.onMessageRead?.(sessionId, messageIds, status);
|
|
697
|
+
await bridge.onMessageRead?.(sessionId, messageIds, status, session);
|
|
671
698
|
} catch (err) {
|
|
672
699
|
console.error(`[PocketPing] Bridge ${bridge.name} read notification error:`, err);
|
|
673
700
|
}
|
|
@@ -676,7 +703,7 @@ var PocketPing = class {
|
|
|
676
703
|
async notifyBridgesEvent(event, session) {
|
|
677
704
|
for (const bridge of this.bridges) {
|
|
678
705
|
try {
|
|
679
|
-
await bridge.
|
|
706
|
+
await bridge.onCustomEvent?.(event, session);
|
|
680
707
|
} catch (err) {
|
|
681
708
|
console.error(`[PocketPing] Bridge ${bridge.name} event notification error:`, err);
|
|
682
709
|
}
|
|
@@ -715,7 +742,7 @@ var PocketPing = class {
|
|
|
715
742
|
"Content-Type": "application/json"
|
|
716
743
|
};
|
|
717
744
|
if (this.config.webhookSecret) {
|
|
718
|
-
const signature = createHmac("sha256", this.config.webhookSecret).update(body).digest("hex");
|
|
745
|
+
const signature = (0, import_crypto.createHmac)("sha256", this.config.webhookSecret).update(body).digest("hex");
|
|
719
746
|
headers["X-PocketPing-Signature"] = `sha256=${signature}`;
|
|
720
747
|
}
|
|
721
748
|
const timeout = this.config.webhookTimeout ?? 5e3;
|
|
@@ -850,7 +877,8 @@ var PocketPing = class {
|
|
|
850
877
|
});
|
|
851
878
|
}
|
|
852
879
|
};
|
|
853
|
-
export
|
|
880
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
881
|
+
0 && (module.exports = {
|
|
854
882
|
MemoryStorage,
|
|
855
883
|
PocketPing
|
|
856
|
-
};
|
|
884
|
+
});
|
|
@@ -28,13 +28,15 @@ interface Bridge {
|
|
|
28
28
|
/** Called when a new chat session is created */
|
|
29
29
|
onNewSession?(session: Session): void | Promise<void>;
|
|
30
30
|
/** Called when a visitor sends a message */
|
|
31
|
-
|
|
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>;
|
|
32
34
|
/** Called when visitor starts/stops typing */
|
|
33
35
|
onTyping?(sessionId: string, isTyping: boolean): void | Promise<void>;
|
|
34
36
|
/** Called when messages are marked as delivered/read */
|
|
35
|
-
onMessageRead?(sessionId: string, messageIds: string[], status: MessageStatus): void | Promise<void>;
|
|
37
|
+
onMessageRead?(sessionId: string, messageIds: string[], status: MessageStatus, session: Session): void | Promise<void>;
|
|
36
38
|
/** Called when a custom event is triggered from the widget */
|
|
37
|
-
|
|
39
|
+
onCustomEvent?(event: CustomEvent, session: Session): void | Promise<void>;
|
|
38
40
|
/** Called when a user identifies themselves via PocketPing.identify() */
|
|
39
41
|
onIdentityUpdate?(session: Session): void | Promise<void>;
|
|
40
42
|
/** Cleanup when bridge is removed */
|
|
@@ -153,12 +155,32 @@ interface ConnectRequest {
|
|
|
153
155
|
/** User identity if already identified */
|
|
154
156
|
identity?: UserIdentity;
|
|
155
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
|
+
}
|
|
156
176
|
interface ConnectResponse {
|
|
157
177
|
sessionId: string;
|
|
158
178
|
visitorId: string;
|
|
159
179
|
operatorOnline: boolean;
|
|
160
180
|
welcomeMessage?: string;
|
|
161
181
|
messages: Message[];
|
|
182
|
+
/** Tracked elements configuration (for SaaS auto-tracking) */
|
|
183
|
+
trackedElements?: TrackedElement[];
|
|
162
184
|
}
|
|
163
185
|
interface SendMessageRequest {
|
|
164
186
|
sessionId: string;
|
|
@@ -396,4 +418,4 @@ declare class MemoryStorage implements Storage {
|
|
|
396
418
|
cleanupOldSessions(olderThan: Date): Promise<number>;
|
|
397
419
|
}
|
|
398
420
|
|
|
399
|
-
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 WebhookPayload };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,13 +28,15 @@ interface Bridge {
|
|
|
28
28
|
/** Called when a new chat session is created */
|
|
29
29
|
onNewSession?(session: Session): void | Promise<void>;
|
|
30
30
|
/** Called when a visitor sends a message */
|
|
31
|
-
|
|
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>;
|
|
32
34
|
/** Called when visitor starts/stops typing */
|
|
33
35
|
onTyping?(sessionId: string, isTyping: boolean): void | Promise<void>;
|
|
34
36
|
/** Called when messages are marked as delivered/read */
|
|
35
|
-
onMessageRead?(sessionId: string, messageIds: string[], status: MessageStatus): void | Promise<void>;
|
|
37
|
+
onMessageRead?(sessionId: string, messageIds: string[], status: MessageStatus, session: Session): void | Promise<void>;
|
|
36
38
|
/** Called when a custom event is triggered from the widget */
|
|
37
|
-
|
|
39
|
+
onCustomEvent?(event: CustomEvent, session: Session): void | Promise<void>;
|
|
38
40
|
/** Called when a user identifies themselves via PocketPing.identify() */
|
|
39
41
|
onIdentityUpdate?(session: Session): void | Promise<void>;
|
|
40
42
|
/** Cleanup when bridge is removed */
|
|
@@ -153,12 +155,32 @@ interface ConnectRequest {
|
|
|
153
155
|
/** User identity if already identified */
|
|
154
156
|
identity?: UserIdentity;
|
|
155
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
|
+
}
|
|
156
176
|
interface ConnectResponse {
|
|
157
177
|
sessionId: string;
|
|
158
178
|
visitorId: string;
|
|
159
179
|
operatorOnline: boolean;
|
|
160
180
|
welcomeMessage?: string;
|
|
161
181
|
messages: Message[];
|
|
182
|
+
/** Tracked elements configuration (for SaaS auto-tracking) */
|
|
183
|
+
trackedElements?: TrackedElement[];
|
|
162
184
|
}
|
|
163
185
|
interface SendMessageRequest {
|
|
164
186
|
sessionId: string;
|
|
@@ -396,4 +418,4 @@ declare class MemoryStorage implements Storage {
|
|
|
396
418
|
cleanupOldSessions(olderThan: Date): Promise<number>;
|
|
397
419
|
}
|
|
398
420
|
|
|
399
|
-
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 WebhookPayload };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
MemoryStorage: () => MemoryStorage,
|
|
24
|
-
PocketPing: () => PocketPing
|
|
25
|
-
});
|
|
26
|
-
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
|
|
28
1
|
// src/pocketping.ts
|
|
29
|
-
|
|
30
|
-
|
|
2
|
+
import { createHmac } from "crypto";
|
|
3
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
31
4
|
|
|
32
5
|
// src/storage/memory.ts
|
|
33
6
|
var MemoryStorage = class {
|
|
@@ -283,7 +256,7 @@ var PocketPing = class {
|
|
|
283
256
|
// ─────────────────────────────────────────────────────────────────
|
|
284
257
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
285
258
|
attachWebSocket(server) {
|
|
286
|
-
this.wss = new
|
|
259
|
+
this.wss = new WebSocketServer({
|
|
287
260
|
server,
|
|
288
261
|
path: "/pocketping/stream"
|
|
289
262
|
});
|
|
@@ -361,7 +334,7 @@ var PocketPing = class {
|
|
|
361
334
|
if (!sockets) return;
|
|
362
335
|
const message = JSON.stringify(event);
|
|
363
336
|
for (const ws of sockets) {
|
|
364
|
-
if (ws.readyState ===
|
|
337
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
365
338
|
ws.send(message);
|
|
366
339
|
}
|
|
367
340
|
}
|
|
@@ -506,7 +479,7 @@ var PocketPing = class {
|
|
|
506
479
|
readAt: status === "read" ? now.toISOString() : void 0
|
|
507
480
|
}
|
|
508
481
|
});
|
|
509
|
-
await this.notifyBridgesRead(request.sessionId, request.messageIds, status);
|
|
482
|
+
await this.notifyBridgesRead(request.sessionId, request.messageIds, status, session);
|
|
510
483
|
return { updated };
|
|
511
484
|
}
|
|
512
485
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -683,7 +656,7 @@ var PocketPing = class {
|
|
|
683
656
|
await bridge.onNewSession?.(args[0]);
|
|
684
657
|
break;
|
|
685
658
|
case "message":
|
|
686
|
-
await bridge.
|
|
659
|
+
await bridge.onVisitorMessage?.(args[0], args[1]);
|
|
687
660
|
break;
|
|
688
661
|
}
|
|
689
662
|
} catch (err) {
|
|
@@ -691,10 +664,10 @@ var PocketPing = class {
|
|
|
691
664
|
}
|
|
692
665
|
}
|
|
693
666
|
}
|
|
694
|
-
async notifyBridgesRead(sessionId, messageIds, status) {
|
|
667
|
+
async notifyBridgesRead(sessionId, messageIds, status, session) {
|
|
695
668
|
for (const bridge of this.bridges) {
|
|
696
669
|
try {
|
|
697
|
-
await bridge.onMessageRead?.(sessionId, messageIds, status);
|
|
670
|
+
await bridge.onMessageRead?.(sessionId, messageIds, status, session);
|
|
698
671
|
} catch (err) {
|
|
699
672
|
console.error(`[PocketPing] Bridge ${bridge.name} read notification error:`, err);
|
|
700
673
|
}
|
|
@@ -703,7 +676,7 @@ var PocketPing = class {
|
|
|
703
676
|
async notifyBridgesEvent(event, session) {
|
|
704
677
|
for (const bridge of this.bridges) {
|
|
705
678
|
try {
|
|
706
|
-
await bridge.
|
|
679
|
+
await bridge.onCustomEvent?.(event, session);
|
|
707
680
|
} catch (err) {
|
|
708
681
|
console.error(`[PocketPing] Bridge ${bridge.name} event notification error:`, err);
|
|
709
682
|
}
|
|
@@ -742,7 +715,7 @@ var PocketPing = class {
|
|
|
742
715
|
"Content-Type": "application/json"
|
|
743
716
|
};
|
|
744
717
|
if (this.config.webhookSecret) {
|
|
745
|
-
const signature =
|
|
718
|
+
const signature = createHmac("sha256", this.config.webhookSecret).update(body).digest("hex");
|
|
746
719
|
headers["X-PocketPing-Signature"] = `sha256=${signature}`;
|
|
747
720
|
}
|
|
748
721
|
const timeout = this.config.webhookTimeout ?? 5e3;
|
|
@@ -877,8 +850,7 @@ var PocketPing = class {
|
|
|
877
850
|
});
|
|
878
851
|
}
|
|
879
852
|
};
|
|
880
|
-
|
|
881
|
-
0 && (module.exports = {
|
|
853
|
+
export {
|
|
882
854
|
MemoryStorage,
|
|
883
855
|
PocketPing
|
|
884
|
-
}
|
|
856
|
+
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pocketping/sdk-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Node.js SDK for implementing PocketPing protocol",
|
|
5
|
-
"main": "dist/index.
|
|
6
|
-
"module": "dist/index.
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
7
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
8
16
|
"files": [
|
|
9
17
|
"dist"
|
|
10
18
|
],
|
|
@@ -23,7 +31,7 @@
|
|
|
23
31
|
"@types/ws": "^8.5.10",
|
|
24
32
|
"tsup": "^8.0.0",
|
|
25
33
|
"typescript": "^5.3.0",
|
|
26
|
-
"vitest": "^
|
|
34
|
+
"vitest": "^4.0.18"
|
|
27
35
|
},
|
|
28
36
|
"peerDependencies": {
|
|
29
37
|
"express": "^4.18.0 || ^5.0.0"
|
|
@@ -46,5 +54,22 @@
|
|
|
46
54
|
"type": "git",
|
|
47
55
|
"url": "https://github.com/Ruwad-io/pocketping.git",
|
|
48
56
|
"directory": "packages/sdk-node"
|
|
57
|
+
},
|
|
58
|
+
"release": {
|
|
59
|
+
"extends": "semantic-release-monorepo",
|
|
60
|
+
"branches": [
|
|
61
|
+
"main"
|
|
62
|
+
],
|
|
63
|
+
"plugins": [
|
|
64
|
+
"@semantic-release/commit-analyzer",
|
|
65
|
+
"@semantic-release/release-notes-generator",
|
|
66
|
+
[
|
|
67
|
+
"@semantic-release/exec",
|
|
68
|
+
{
|
|
69
|
+
"prepareCmd": "npm pkg set version=${nextRelease.version}"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"@semantic-release/github"
|
|
73
|
+
]
|
|
49
74
|
}
|
|
50
75
|
}
|