@pocketping/widget 0.1.0 → 0.2.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 +89 -2
- package/dist/index.d.mts +191 -1
- package/dist/index.d.ts +191 -1
- package/dist/index.global.js +264 -4
- package/dist/index.js +272 -5
- package/dist/index.mjs +264 -4
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -23,10 +23,17 @@ __export(index_exports, {
|
|
|
23
23
|
close: () => close,
|
|
24
24
|
default: () => index_default,
|
|
25
25
|
destroy: () => destroy,
|
|
26
|
+
getIdentity: () => getIdentity,
|
|
27
|
+
identify: () => identify,
|
|
26
28
|
init: () => init,
|
|
29
|
+
offEvent: () => offEvent,
|
|
30
|
+
on: () => on,
|
|
31
|
+
onEvent: () => onEvent,
|
|
27
32
|
open: () => open,
|
|
33
|
+
reset: () => reset,
|
|
28
34
|
sendMessage: () => sendMessage,
|
|
29
|
-
toggle: () => toggle
|
|
35
|
+
toggle: () => toggle,
|
|
36
|
+
trigger: () => trigger
|
|
30
37
|
});
|
|
31
38
|
module.exports = __toCommonJS(index_exports);
|
|
32
39
|
var import_preact2 = require("preact");
|
|
@@ -629,6 +636,9 @@ function StatusIcon({ status }) {
|
|
|
629
636
|
return null;
|
|
630
637
|
}
|
|
631
638
|
|
|
639
|
+
// src/version.ts
|
|
640
|
+
var VERSION = "0.2.0";
|
|
641
|
+
|
|
632
642
|
// src/client.ts
|
|
633
643
|
var PocketPingClient = class {
|
|
634
644
|
constructor(config) {
|
|
@@ -636,6 +646,7 @@ var PocketPingClient = class {
|
|
|
636
646
|
this.ws = null;
|
|
637
647
|
this.isOpen = false;
|
|
638
648
|
this.listeners = /* @__PURE__ */ new Map();
|
|
649
|
+
this.customEventHandlers = /* @__PURE__ */ new Map();
|
|
639
650
|
this.reconnectAttempts = 0;
|
|
640
651
|
this.maxReconnectAttempts = 5;
|
|
641
652
|
this.reconnectTimeout = null;
|
|
@@ -647,6 +658,7 @@ var PocketPingClient = class {
|
|
|
647
658
|
async connect() {
|
|
648
659
|
const visitorId = this.getOrCreateVisitorId();
|
|
649
660
|
const storedSessionId = this.getStoredSessionId();
|
|
661
|
+
const storedIdentity = this.getStoredIdentity();
|
|
650
662
|
const response = await this.fetch("/connect", {
|
|
651
663
|
method: "POST",
|
|
652
664
|
body: JSON.stringify({
|
|
@@ -660,14 +672,17 @@ var PocketPingClient = class {
|
|
|
660
672
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
661
673
|
language: navigator.language,
|
|
662
674
|
screenResolution: `${window.screen.width}x${window.screen.height}`
|
|
663
|
-
}
|
|
675
|
+
},
|
|
676
|
+
// Include stored identity if available
|
|
677
|
+
identity: storedIdentity || void 0
|
|
664
678
|
})
|
|
665
679
|
});
|
|
666
680
|
this.session = {
|
|
667
681
|
sessionId: response.sessionId,
|
|
668
682
|
visitorId: response.visitorId,
|
|
669
683
|
operatorOnline: response.operatorOnline ?? false,
|
|
670
|
-
messages: response.messages ?? []
|
|
684
|
+
messages: response.messages ?? [],
|
|
685
|
+
identity: response.identity || storedIdentity || void 0
|
|
671
686
|
};
|
|
672
687
|
this.storeSessionId(response.sessionId);
|
|
673
688
|
this.connectWebSocket();
|
|
@@ -790,6 +805,69 @@ var PocketPingClient = class {
|
|
|
790
805
|
return this.fetch("/presence", { method: "GET" });
|
|
791
806
|
}
|
|
792
807
|
// ─────────────────────────────────────────────────────────────────
|
|
808
|
+
// User Identity
|
|
809
|
+
// ─────────────────────────────────────────────────────────────────
|
|
810
|
+
/**
|
|
811
|
+
* Identify the current user with metadata
|
|
812
|
+
* Call after user logs in or when user data becomes available
|
|
813
|
+
* @param identity - User identity data with required id field
|
|
814
|
+
* @example
|
|
815
|
+
* PocketPing.identify({
|
|
816
|
+
* id: 'user_123',
|
|
817
|
+
* email: 'john@example.com',
|
|
818
|
+
* name: 'John Doe',
|
|
819
|
+
* plan: 'pro',
|
|
820
|
+
* company: 'Acme Inc'
|
|
821
|
+
* })
|
|
822
|
+
*/
|
|
823
|
+
async identify(identity) {
|
|
824
|
+
if (!identity?.id) {
|
|
825
|
+
throw new Error("[PocketPing] identity.id is required");
|
|
826
|
+
}
|
|
827
|
+
this.storeIdentity(identity);
|
|
828
|
+
if (this.session) {
|
|
829
|
+
try {
|
|
830
|
+
await this.fetch("/identify", {
|
|
831
|
+
method: "POST",
|
|
832
|
+
body: JSON.stringify({
|
|
833
|
+
sessionId: this.session.sessionId,
|
|
834
|
+
identity
|
|
835
|
+
})
|
|
836
|
+
});
|
|
837
|
+
this.session.identity = identity;
|
|
838
|
+
this.emit("identify", identity);
|
|
839
|
+
} catch (err) {
|
|
840
|
+
console.error("[PocketPing] Failed to identify:", err);
|
|
841
|
+
throw err;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Reset the user identity and optionally start a new session
|
|
847
|
+
* Call on user logout to clear user data
|
|
848
|
+
* @param options - Optional settings: { newSession: boolean }
|
|
849
|
+
*/
|
|
850
|
+
async reset(options) {
|
|
851
|
+
this.clearIdentity();
|
|
852
|
+
if (this.session) {
|
|
853
|
+
this.session.identity = void 0;
|
|
854
|
+
}
|
|
855
|
+
if (options?.newSession) {
|
|
856
|
+
localStorage.removeItem("pocketping_session_id");
|
|
857
|
+
localStorage.removeItem("pocketping_visitor_id");
|
|
858
|
+
this.disconnect();
|
|
859
|
+
await this.connect();
|
|
860
|
+
}
|
|
861
|
+
this.emit("reset", null);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Get the current user identity
|
|
865
|
+
* @returns UserIdentity or null if not identified
|
|
866
|
+
*/
|
|
867
|
+
getIdentity() {
|
|
868
|
+
return this.session?.identity || this.getStoredIdentity();
|
|
869
|
+
}
|
|
870
|
+
// ─────────────────────────────────────────────────────────────────
|
|
793
871
|
// State
|
|
794
872
|
// ─────────────────────────────────────────────────────────────────
|
|
795
873
|
getSession() {
|
|
@@ -832,6 +910,67 @@ var PocketPingClient = class {
|
|
|
832
910
|
this.listeners.get(event)?.forEach((listener) => listener(data));
|
|
833
911
|
}
|
|
834
912
|
// ─────────────────────────────────────────────────────────────────
|
|
913
|
+
// Custom Events (bidirectional)
|
|
914
|
+
// ─────────────────────────────────────────────────────────────────
|
|
915
|
+
/**
|
|
916
|
+
* Trigger a custom event to the backend
|
|
917
|
+
* @param eventName - The name of the event (e.g., 'clicked_pricing', 'viewed_demo')
|
|
918
|
+
* @param data - Optional payload to send with the event
|
|
919
|
+
* @example
|
|
920
|
+
* PocketPing.trigger('clicked_cta', { button: 'signup', page: '/pricing' })
|
|
921
|
+
*/
|
|
922
|
+
trigger(eventName, data) {
|
|
923
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
924
|
+
console.warn("[PocketPing] Cannot trigger event: WebSocket not connected");
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const event = {
|
|
928
|
+
name: eventName,
|
|
929
|
+
data,
|
|
930
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
931
|
+
};
|
|
932
|
+
this.ws.send(JSON.stringify({
|
|
933
|
+
type: "event",
|
|
934
|
+
data: event
|
|
935
|
+
}));
|
|
936
|
+
this.emit(`event:${eventName}`, event);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Subscribe to custom events from the backend
|
|
940
|
+
* @param eventName - The name of the event to listen for (e.g., 'show_offer', 'open_chat')
|
|
941
|
+
* @param handler - Callback function when event is received
|
|
942
|
+
* @returns Unsubscribe function
|
|
943
|
+
* @example
|
|
944
|
+
* const unsubscribe = PocketPing.onEvent('show_offer', (data) => {
|
|
945
|
+
* showPopup(data.message)
|
|
946
|
+
* })
|
|
947
|
+
*/
|
|
948
|
+
onEvent(eventName, handler) {
|
|
949
|
+
if (!this.customEventHandlers.has(eventName)) {
|
|
950
|
+
this.customEventHandlers.set(eventName, /* @__PURE__ */ new Set());
|
|
951
|
+
}
|
|
952
|
+
this.customEventHandlers.get(eventName).add(handler);
|
|
953
|
+
return () => {
|
|
954
|
+
this.customEventHandlers.get(eventName)?.delete(handler);
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Unsubscribe from a custom event
|
|
959
|
+
* @param eventName - The name of the event
|
|
960
|
+
* @param handler - The handler to remove
|
|
961
|
+
*/
|
|
962
|
+
offEvent(eventName, handler) {
|
|
963
|
+
this.customEventHandlers.get(eventName)?.delete(handler);
|
|
964
|
+
}
|
|
965
|
+
emitCustomEvent(event) {
|
|
966
|
+
const handlers = this.customEventHandlers.get(event.name);
|
|
967
|
+
if (handlers) {
|
|
968
|
+
handlers.forEach((handler) => handler(event.data, event));
|
|
969
|
+
}
|
|
970
|
+
this.emit("event", event);
|
|
971
|
+
this.emit(`event:${event.name}`, event);
|
|
972
|
+
}
|
|
973
|
+
// ─────────────────────────────────────────────────────────────────
|
|
835
974
|
// WebSocket
|
|
836
975
|
// ─────────────────────────────────────────────────────────────────
|
|
837
976
|
connectWebSocket() {
|
|
@@ -929,6 +1068,40 @@ var PocketPingClient = class {
|
|
|
929
1068
|
}
|
|
930
1069
|
this.emit("read", readData);
|
|
931
1070
|
break;
|
|
1071
|
+
case "event":
|
|
1072
|
+
const customEvent = event.data;
|
|
1073
|
+
this.emitCustomEvent(customEvent);
|
|
1074
|
+
break;
|
|
1075
|
+
case "version_warning":
|
|
1076
|
+
const versionWarning = event.data;
|
|
1077
|
+
this.handleVersionWarning(versionWarning);
|
|
1078
|
+
break;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
// ─────────────────────────────────────────────────────────────────
|
|
1082
|
+
// Version Management
|
|
1083
|
+
// ─────────────────────────────────────────────────────────────────
|
|
1084
|
+
handleVersionWarning(warning) {
|
|
1085
|
+
const prefix = "[PocketPing]";
|
|
1086
|
+
const upgradeHint = warning.upgradeUrl ? ` Upgrade: ${warning.upgradeUrl}` : " Update your widget to the latest version.";
|
|
1087
|
+
switch (warning.severity) {
|
|
1088
|
+
case "error":
|
|
1089
|
+
console.error(`${prefix} \u{1F6A8} VERSION ERROR: ${warning.message}${upgradeHint}`);
|
|
1090
|
+
console.error(`${prefix} Current: ${warning.currentVersion}, Required: ${warning.minVersion || "unknown"}`);
|
|
1091
|
+
break;
|
|
1092
|
+
case "warning":
|
|
1093
|
+
console.warn(`${prefix} \u26A0\uFE0F VERSION WARNING: ${warning.message}${upgradeHint}`);
|
|
1094
|
+
console.warn(`${prefix} Current: ${warning.currentVersion}, Latest: ${warning.latestVersion || "unknown"}`);
|
|
1095
|
+
break;
|
|
1096
|
+
case "info":
|
|
1097
|
+
console.info(`${prefix} \u2139\uFE0F ${warning.message}`);
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
this.emit("versionWarning", warning);
|
|
1101
|
+
this.config.onVersionWarning?.(warning);
|
|
1102
|
+
if (!warning.canContinue) {
|
|
1103
|
+
console.error(`${prefix} Widget is incompatible with backend. Please update immediately.`);
|
|
1104
|
+
this.disconnect();
|
|
932
1105
|
}
|
|
933
1106
|
}
|
|
934
1107
|
scheduleReconnect() {
|
|
@@ -974,15 +1147,46 @@ var PocketPingClient = class {
|
|
|
974
1147
|
...options,
|
|
975
1148
|
headers: {
|
|
976
1149
|
"Content-Type": "application/json",
|
|
1150
|
+
"X-PocketPing-Version": VERSION,
|
|
977
1151
|
...options.headers
|
|
978
1152
|
}
|
|
979
1153
|
});
|
|
1154
|
+
this.checkVersionHeaders(response);
|
|
980
1155
|
if (!response.ok) {
|
|
981
1156
|
const error = await response.text();
|
|
982
1157
|
throw new Error(`PocketPing API error: ${response.status} ${error}`);
|
|
983
1158
|
}
|
|
984
1159
|
return response.json();
|
|
985
1160
|
}
|
|
1161
|
+
checkVersionHeaders(response) {
|
|
1162
|
+
const versionStatus = response.headers.get("X-PocketPing-Version-Status");
|
|
1163
|
+
const minVersion = response.headers.get("X-PocketPing-Min-Version");
|
|
1164
|
+
const latestVersion = response.headers.get("X-PocketPing-Latest-Version");
|
|
1165
|
+
const versionMessage = response.headers.get("X-PocketPing-Version-Message");
|
|
1166
|
+
if (!versionStatus || versionStatus === "ok") {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
let severity = "info";
|
|
1170
|
+
let canContinue = true;
|
|
1171
|
+
if (versionStatus === "deprecated") {
|
|
1172
|
+
severity = "warning";
|
|
1173
|
+
} else if (versionStatus === "unsupported") {
|
|
1174
|
+
severity = "error";
|
|
1175
|
+
canContinue = false;
|
|
1176
|
+
} else if (versionStatus === "outdated") {
|
|
1177
|
+
severity = "info";
|
|
1178
|
+
}
|
|
1179
|
+
const warning = {
|
|
1180
|
+
severity,
|
|
1181
|
+
message: versionMessage || `Widget version ${VERSION} is ${versionStatus}`,
|
|
1182
|
+
currentVersion: VERSION,
|
|
1183
|
+
minVersion: minVersion || void 0,
|
|
1184
|
+
latestVersion: latestVersion || void 0,
|
|
1185
|
+
canContinue,
|
|
1186
|
+
upgradeUrl: "https://docs.pocketping.io/widget/installation"
|
|
1187
|
+
};
|
|
1188
|
+
this.handleVersionWarning(warning);
|
|
1189
|
+
}
|
|
986
1190
|
// ─────────────────────────────────────────────────────────────────
|
|
987
1191
|
// Storage
|
|
988
1192
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -1001,6 +1205,20 @@ var PocketPingClient = class {
|
|
|
1001
1205
|
storeSessionId(sessionId) {
|
|
1002
1206
|
localStorage.setItem("pocketping_session_id", sessionId);
|
|
1003
1207
|
}
|
|
1208
|
+
getStoredIdentity() {
|
|
1209
|
+
try {
|
|
1210
|
+
const stored = localStorage.getItem("pocketping_user_identity");
|
|
1211
|
+
return stored ? JSON.parse(stored) : null;
|
|
1212
|
+
} catch {
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
storeIdentity(identity) {
|
|
1217
|
+
localStorage.setItem("pocketping_user_identity", JSON.stringify(identity));
|
|
1218
|
+
}
|
|
1219
|
+
clearIdentity() {
|
|
1220
|
+
localStorage.removeItem("pocketping_user_identity");
|
|
1221
|
+
}
|
|
1004
1222
|
generateId() {
|
|
1005
1223
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;
|
|
1006
1224
|
}
|
|
@@ -1053,6 +1271,48 @@ function sendMessage(content) {
|
|
|
1053
1271
|
}
|
|
1054
1272
|
return client.sendMessage(content);
|
|
1055
1273
|
}
|
|
1274
|
+
function trigger(eventName, data) {
|
|
1275
|
+
if (!client) {
|
|
1276
|
+
console.warn("[PocketPing] Not initialized, cannot trigger event");
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
client.trigger(eventName, data);
|
|
1280
|
+
}
|
|
1281
|
+
function onEvent(eventName, handler) {
|
|
1282
|
+
if (!client) {
|
|
1283
|
+
console.warn("[PocketPing] Not initialized, cannot subscribe to event");
|
|
1284
|
+
return () => {
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
return client.onEvent(eventName, handler);
|
|
1288
|
+
}
|
|
1289
|
+
function offEvent(eventName, handler) {
|
|
1290
|
+
client?.offEvent(eventName, handler);
|
|
1291
|
+
}
|
|
1292
|
+
async function identify(identity) {
|
|
1293
|
+
if (!client) {
|
|
1294
|
+
throw new Error("[PocketPing] Not initialized");
|
|
1295
|
+
}
|
|
1296
|
+
return client.identify(identity);
|
|
1297
|
+
}
|
|
1298
|
+
async function reset(options) {
|
|
1299
|
+
if (!client) {
|
|
1300
|
+
console.warn("[PocketPing] Not initialized");
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
return client.reset(options);
|
|
1304
|
+
}
|
|
1305
|
+
function getIdentity() {
|
|
1306
|
+
return client?.getIdentity() || null;
|
|
1307
|
+
}
|
|
1308
|
+
function on(eventName, handler) {
|
|
1309
|
+
if (!client) {
|
|
1310
|
+
console.warn("[PocketPing] Not initialized, cannot subscribe to event");
|
|
1311
|
+
return () => {
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
return client.on(eventName, handler);
|
|
1315
|
+
}
|
|
1056
1316
|
if (typeof document !== "undefined") {
|
|
1057
1317
|
const script = document.currentScript;
|
|
1058
1318
|
if (script?.dataset.endpoint) {
|
|
@@ -1063,13 +1323,20 @@ if (typeof document !== "undefined") {
|
|
|
1063
1323
|
});
|
|
1064
1324
|
}
|
|
1065
1325
|
}
|
|
1066
|
-
var index_default = { init, destroy, open, close, toggle, sendMessage };
|
|
1326
|
+
var index_default = { init, destroy, open, close, toggle, sendMessage, trigger, onEvent, offEvent, on, identify, reset, getIdentity };
|
|
1067
1327
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1068
1328
|
0 && (module.exports = {
|
|
1069
1329
|
close,
|
|
1070
1330
|
destroy,
|
|
1331
|
+
getIdentity,
|
|
1332
|
+
identify,
|
|
1071
1333
|
init,
|
|
1334
|
+
offEvent,
|
|
1335
|
+
on,
|
|
1336
|
+
onEvent,
|
|
1072
1337
|
open,
|
|
1338
|
+
reset,
|
|
1073
1339
|
sendMessage,
|
|
1074
|
-
toggle
|
|
1340
|
+
toggle,
|
|
1341
|
+
trigger
|
|
1075
1342
|
});
|