@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/dist/index.js CHANGED
@@ -1,32 +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
- var import_ws = require("ws");
2
+ import { createHmac } from "crypto";
3
+ import { WebSocketServer, WebSocket } from "ws";
30
4
 
31
5
  // src/storage/memory.ts
32
6
  var MemoryStorage = class {
@@ -131,11 +105,27 @@ function parseUserAgent(userAgent) {
131
105
  else if (ua.includes("iphone") || ua.includes("ipad")) os = "iOS";
132
106
  return { deviceType, browser, os };
133
107
  }
108
+ function parseVersion(version) {
109
+ return version.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
110
+ }
111
+ function compareVersions(a, b) {
112
+ const vA = parseVersion(a);
113
+ const vB = parseVersion(b);
114
+ const len = Math.max(vA.length, vB.length);
115
+ for (let i = 0; i < len; i++) {
116
+ const numA = vA[i] ?? 0;
117
+ const numB = vB[i] ?? 0;
118
+ if (numA < numB) return -1;
119
+ if (numA > numB) return 1;
120
+ }
121
+ return 0;
122
+ }
134
123
  var PocketPing = class {
135
124
  constructor(config = {}) {
136
125
  this.wss = null;
137
126
  this.sessionSockets = /* @__PURE__ */ new Map();
138
127
  this.operatorOnline = false;
128
+ this.eventHandlers = /* @__PURE__ */ new Map();
139
129
  this.config = config;
140
130
  this.storage = this.initStorage(config.storage);
141
131
  this.bridges = config.bridges ?? [];
@@ -155,16 +145,32 @@ var PocketPing = class {
155
145
  const path = url.pathname.replace(/^\/+/, "").replace(/\/+$/, "");
156
146
  res.setHeader("Access-Control-Allow-Origin", "*");
157
147
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
158
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
148
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-PocketPing-Version");
149
+ res.setHeader("Access-Control-Expose-Headers", "X-PocketPing-Version-Status, X-PocketPing-Min-Version, X-PocketPing-Latest-Version, X-PocketPing-Version-Message");
159
150
  if (req.method === "OPTIONS") {
160
151
  res.statusCode = 204;
161
152
  res.end();
162
153
  return;
163
154
  }
155
+ const widgetVersion = req.headers["x-pocketping-version"];
156
+ const versionCheck = this.checkWidgetVersion(widgetVersion);
157
+ this.setVersionHeaders(res, versionCheck);
158
+ if (!versionCheck.canContinue) {
159
+ res.statusCode = 426;
160
+ res.setHeader("Content-Type", "application/json");
161
+ res.end(JSON.stringify({
162
+ error: "Widget version unsupported",
163
+ message: versionCheck.message,
164
+ minVersion: versionCheck.minVersion,
165
+ upgradeUrl: this.config.versionUpgradeUrl || "https://docs.pocketping.io/widget/installation"
166
+ }));
167
+ return;
168
+ }
164
169
  try {
165
170
  const body = await this.parseBody(req);
166
171
  const query = Object.fromEntries(url.searchParams);
167
172
  let result;
173
+ let sessionId;
168
174
  switch (path) {
169
175
  case "connect": {
170
176
  const connectReq = body;
@@ -183,7 +189,9 @@ var PocketPing = class {
183
189
  ...uaInfo
184
190
  };
185
191
  }
186
- result = await this.handleConnect(connectReq);
192
+ const connectResult = await this.handleConnect(connectReq);
193
+ sessionId = connectResult.sessionId;
194
+ result = connectResult;
187
195
  break;
188
196
  }
189
197
  case "message":
@@ -201,6 +209,9 @@ var PocketPing = class {
201
209
  case "read":
202
210
  result = await this.handleRead(body);
203
211
  break;
212
+ case "identify":
213
+ result = await this.handleIdentify(body);
214
+ break;
204
215
  default:
205
216
  if (next) {
206
217
  next();
@@ -213,6 +224,11 @@ var PocketPing = class {
213
224
  res.setHeader("Content-Type", "application/json");
214
225
  res.statusCode = 200;
215
226
  res.end(JSON.stringify(result));
227
+ if (sessionId && versionCheck.status !== "ok") {
228
+ setTimeout(() => {
229
+ this.sendVersionWarning(sessionId, versionCheck);
230
+ }, 500);
231
+ }
216
232
  } catch (error) {
217
233
  console.error("[PocketPing] Error:", error);
218
234
  res.statusCode = 500;
@@ -240,7 +256,7 @@ var PocketPing = class {
240
256
  // ─────────────────────────────────────────────────────────────────
241
257
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
258
  attachWebSocket(server) {
243
- this.wss = new import_ws.WebSocketServer({
259
+ this.wss = new WebSocketServer({
244
260
  server,
245
261
  path: "/pocketping/stream"
246
262
  });
@@ -276,14 +292,49 @@ var PocketPing = class {
276
292
  data: event.data
277
293
  });
278
294
  break;
295
+ case "event":
296
+ const customEvent = event.data;
297
+ customEvent.sessionId = sessionId;
298
+ await this.handleCustomEvent(sessionId, customEvent);
299
+ break;
300
+ }
301
+ }
302
+ async handleCustomEvent(sessionId, event) {
303
+ const session = await this.storage.getSession(sessionId);
304
+ if (!session) {
305
+ console.warn(`[PocketPing] Event received for unknown session: ${sessionId}`);
306
+ return;
307
+ }
308
+ const handlers = this.eventHandlers.get(event.name);
309
+ if (handlers) {
310
+ for (const handler of handlers) {
311
+ try {
312
+ await handler(event, session);
313
+ } catch (err) {
314
+ console.error(`[PocketPing] Event handler error for '${event.name}':`, err);
315
+ }
316
+ }
317
+ }
318
+ const wildcardHandlers = this.eventHandlers.get("*");
319
+ if (wildcardHandlers) {
320
+ for (const handler of wildcardHandlers) {
321
+ try {
322
+ await handler(event, session);
323
+ } catch (err) {
324
+ console.error(`[PocketPing] Wildcard event handler error:`, err);
325
+ }
326
+ }
279
327
  }
328
+ await this.config.onEvent?.(event, session);
329
+ await this.notifyBridgesEvent(event, session);
330
+ this.forwardToWebhook(event, session);
280
331
  }
281
332
  broadcastToSession(sessionId, event) {
282
333
  const sockets = this.sessionSockets.get(sessionId);
283
334
  if (!sockets) return;
284
335
  const message = JSON.stringify(event);
285
336
  for (const ws of sockets) {
286
- if (ws.readyState === import_ws.WebSocket.OPEN) {
337
+ if (ws.readyState === WebSocket.OPEN) {
287
338
  ws.send(message);
288
339
  }
289
340
  }
@@ -307,20 +358,31 @@ var PocketPing = class {
307
358
  lastActivity: /* @__PURE__ */ new Date(),
308
359
  operatorOnline: this.operatorOnline,
309
360
  aiActive: false,
310
- metadata: request.metadata
361
+ metadata: request.metadata,
362
+ identity: request.identity
311
363
  };
312
364
  await this.storage.createSession(session);
313
365
  await this.notifyBridges("new_session", session);
314
366
  await this.config.onNewSession?.(session);
315
- } else if (request.metadata) {
316
- if (session.metadata) {
317
- request.metadata.ip = session.metadata.ip ?? request.metadata.ip;
318
- request.metadata.country = session.metadata.country ?? request.metadata.country;
319
- request.metadata.city = session.metadata.city ?? request.metadata.city;
367
+ } else {
368
+ let needsUpdate = false;
369
+ if (request.metadata) {
370
+ if (session.metadata) {
371
+ request.metadata.ip = session.metadata.ip ?? request.metadata.ip;
372
+ request.metadata.country = session.metadata.country ?? request.metadata.country;
373
+ request.metadata.city = session.metadata.city ?? request.metadata.city;
374
+ }
375
+ session.metadata = request.metadata;
376
+ needsUpdate = true;
377
+ }
378
+ if (request.identity) {
379
+ session.identity = request.identity;
380
+ needsUpdate = true;
381
+ }
382
+ if (needsUpdate) {
383
+ session.lastActivity = /* @__PURE__ */ new Date();
384
+ await this.storage.updateSession(session);
320
385
  }
321
- session.metadata = request.metadata;
322
- session.lastActivity = /* @__PURE__ */ new Date();
323
- await this.storage.updateSession(session);
324
386
  }
325
387
  const messages = await this.storage.getMessages(session.id);
326
388
  return {
@@ -417,10 +479,39 @@ var PocketPing = class {
417
479
  readAt: status === "read" ? now.toISOString() : void 0
418
480
  }
419
481
  });
420
- await this.notifyBridgesRead(request.sessionId, request.messageIds, status);
482
+ await this.notifyBridgesRead(request.sessionId, request.messageIds, status, session);
421
483
  return { updated };
422
484
  }
423
485
  // ─────────────────────────────────────────────────────────────────
486
+ // User Identity
487
+ // ─────────────────────────────────────────────────────────────────
488
+ /**
489
+ * Handle user identification from widget
490
+ * Called when visitor calls PocketPing.identify()
491
+ */
492
+ async handleIdentify(request) {
493
+ if (!request.identity?.id) {
494
+ throw new Error("identity.id is required");
495
+ }
496
+ const session = await this.storage.getSession(request.sessionId);
497
+ if (!session) {
498
+ throw new Error("Session not found");
499
+ }
500
+ session.identity = request.identity;
501
+ session.lastActivity = /* @__PURE__ */ new Date();
502
+ await this.storage.updateSession(session);
503
+ await this.notifyBridgesIdentity(session);
504
+ await this.config.onIdentify?.(session);
505
+ this.forwardIdentityToWebhook(session);
506
+ return { ok: true };
507
+ }
508
+ /**
509
+ * Get a session by ID
510
+ */
511
+ async getSession(sessionId) {
512
+ return this.storage.getSession(sessionId);
513
+ }
514
+ // ─────────────────────────────────────────────────────────────────
424
515
  // Operator Actions (for bridges)
425
516
  // ─────────────────────────────────────────────────────────────────
426
517
  async sendOperatorMessage(sessionId, content) {
@@ -448,6 +539,113 @@ var PocketPing = class {
448
539
  }
449
540
  }
450
541
  // ─────────────────────────────────────────────────────────────────
542
+ // Custom Events (bidirectional)
543
+ // ─────────────────────────────────────────────────────────────────
544
+ /**
545
+ * Subscribe to custom events from widgets
546
+ * @param eventName - The name of the event to listen for, or '*' for all events
547
+ * @param handler - Callback function when event is received
548
+ * @returns Unsubscribe function
549
+ * @example
550
+ * // Listen for specific event
551
+ * pp.onEvent('clicked_pricing', async (event, session) => {
552
+ * console.log(`User ${session.visitorId} clicked pricing: ${event.data?.plan}`)
553
+ * })
554
+ *
555
+ * // Listen for all events
556
+ * pp.onEvent('*', async (event, session) => {
557
+ * console.log(`Event: ${event.name}`, event.data)
558
+ * })
559
+ */
560
+ onEvent(eventName, handler) {
561
+ if (!this.eventHandlers.has(eventName)) {
562
+ this.eventHandlers.set(eventName, /* @__PURE__ */ new Set());
563
+ }
564
+ this.eventHandlers.get(eventName).add(handler);
565
+ return () => {
566
+ this.eventHandlers.get(eventName)?.delete(handler);
567
+ };
568
+ }
569
+ /**
570
+ * Unsubscribe from a custom event
571
+ * @param eventName - The name of the event
572
+ * @param handler - The handler to remove
573
+ */
574
+ offEvent(eventName, handler) {
575
+ this.eventHandlers.get(eventName)?.delete(handler);
576
+ }
577
+ /**
578
+ * Send a custom event to a specific widget/session
579
+ * @param sessionId - The session ID to send the event to
580
+ * @param eventName - The name of the event
581
+ * @param data - Optional payload to send with the event
582
+ * @example
583
+ * // Send a promotion offer to a specific user
584
+ * pp.emitEvent('session-123', 'show_offer', {
585
+ * discount: 20,
586
+ * code: 'SAVE20',
587
+ * message: 'Special offer just for you!'
588
+ * })
589
+ */
590
+ emitEvent(sessionId, eventName, data) {
591
+ const event = {
592
+ name: eventName,
593
+ data,
594
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
595
+ sessionId
596
+ };
597
+ this.broadcastToSession(sessionId, {
598
+ type: "event",
599
+ data: event
600
+ });
601
+ }
602
+ /**
603
+ * Broadcast a custom event to all connected widgets
604
+ * @param eventName - The name of the event
605
+ * @param data - Optional payload to send with the event
606
+ * @example
607
+ * // Notify all users about maintenance
608
+ * pp.broadcastEvent('maintenance_warning', {
609
+ * message: 'Site will be down for maintenance in 5 minutes'
610
+ * })
611
+ */
612
+ broadcastEvent(eventName, data) {
613
+ const event = {
614
+ name: eventName,
615
+ data,
616
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
617
+ };
618
+ for (const sessionId of this.sessionSockets.keys()) {
619
+ event.sessionId = sessionId;
620
+ this.broadcastToSession(sessionId, {
621
+ type: "event",
622
+ data: event
623
+ });
624
+ }
625
+ }
626
+ /**
627
+ * Process a custom event server-side (runs handlers, bridges, webhooks)
628
+ * Useful for server-side automation or triggering events programmatically
629
+ * @param sessionId - The session ID to associate with the event
630
+ * @param eventName - The name of the event
631
+ * @param data - Optional payload for the event
632
+ * @example
633
+ * // Trigger event from backend logic (e.g., after purchase)
634
+ * await pp.triggerEvent('session-123', 'purchase_completed', {
635
+ * orderId: 'order-456',
636
+ * amount: 99.99
637
+ * })
638
+ */
639
+ async triggerEvent(sessionId, eventName, data) {
640
+ const event = {
641
+ name: eventName,
642
+ data,
643
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
644
+ sessionId
645
+ };
646
+ await this.handleCustomEvent(sessionId, event);
647
+ }
648
+ // ─────────────────────────────────────────────────────────────────
451
649
  // Bridges
452
650
  // ─────────────────────────────────────────────────────────────────
453
651
  async notifyBridges(event, ...args) {
@@ -458,7 +656,7 @@ var PocketPing = class {
458
656
  await bridge.onNewSession?.(args[0]);
459
657
  break;
460
658
  case "message":
461
- await bridge.onMessage?.(args[0], args[1]);
659
+ await bridge.onVisitorMessage?.(args[0], args[1]);
462
660
  break;
463
661
  }
464
662
  } catch (err) {
@@ -466,15 +664,95 @@ var PocketPing = class {
466
664
  }
467
665
  }
468
666
  }
469
- async notifyBridgesRead(sessionId, messageIds, status) {
667
+ async notifyBridgesRead(sessionId, messageIds, status, session) {
470
668
  for (const bridge of this.bridges) {
471
669
  try {
472
- await bridge.onMessageRead?.(sessionId, messageIds, status);
670
+ await bridge.onMessageRead?.(sessionId, messageIds, status, session);
473
671
  } catch (err) {
474
672
  console.error(`[PocketPing] Bridge ${bridge.name} read notification error:`, err);
475
673
  }
476
674
  }
477
675
  }
676
+ async notifyBridgesEvent(event, session) {
677
+ for (const bridge of this.bridges) {
678
+ try {
679
+ await bridge.onCustomEvent?.(event, session);
680
+ } catch (err) {
681
+ console.error(`[PocketPing] Bridge ${bridge.name} event notification error:`, err);
682
+ }
683
+ }
684
+ }
685
+ async notifyBridgesIdentity(session) {
686
+ for (const bridge of this.bridges) {
687
+ try {
688
+ await bridge.onIdentityUpdate?.(session);
689
+ } catch (err) {
690
+ console.error(`[PocketPing] Bridge ${bridge.name} identity notification error:`, err);
691
+ }
692
+ }
693
+ }
694
+ // ─────────────────────────────────────────────────────────────────
695
+ // Webhook Forwarding
696
+ // ─────────────────────────────────────────────────────────────────
697
+ /**
698
+ * Forward custom event to configured webhook URL (non-blocking)
699
+ * Used for integrations with Zapier, Make, n8n, or custom backends
700
+ */
701
+ forwardToWebhook(event, session) {
702
+ if (!this.config.webhookUrl) return;
703
+ const payload = {
704
+ event,
705
+ session: {
706
+ id: session.id,
707
+ visitorId: session.visitorId,
708
+ metadata: session.metadata,
709
+ identity: session.identity
710
+ },
711
+ sentAt: (/* @__PURE__ */ new Date()).toISOString()
712
+ };
713
+ const body = JSON.stringify(payload);
714
+ const headers = {
715
+ "Content-Type": "application/json"
716
+ };
717
+ if (this.config.webhookSecret) {
718
+ const signature = createHmac("sha256", this.config.webhookSecret).update(body).digest("hex");
719
+ headers["X-PocketPing-Signature"] = `sha256=${signature}`;
720
+ }
721
+ const timeout = this.config.webhookTimeout ?? 5e3;
722
+ const controller = new AbortController();
723
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
724
+ fetch(this.config.webhookUrl, {
725
+ method: "POST",
726
+ headers,
727
+ body,
728
+ signal: controller.signal
729
+ }).then((response) => {
730
+ clearTimeout(timeoutId);
731
+ if (!response.ok) {
732
+ console.error(`[PocketPing] Webhook returned ${response.status}: ${response.statusText}`);
733
+ }
734
+ }).catch((err) => {
735
+ clearTimeout(timeoutId);
736
+ if (err.name === "AbortError") {
737
+ console.error(`[PocketPing] Webhook timed out after ${timeout}ms`);
738
+ } else {
739
+ console.error(`[PocketPing] Webhook error:`, err.message);
740
+ }
741
+ });
742
+ }
743
+ /**
744
+ * Forward identity update to webhook as a special event
745
+ */
746
+ forwardIdentityToWebhook(session) {
747
+ if (!this.config.webhookUrl || !session.identity) return;
748
+ const event = {
749
+ name: "identify",
750
+ data: session.identity,
751
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
752
+ sessionId: session.id
753
+ };
754
+ this.forwardToWebhook(event, session);
755
+ }
478
756
  addBridge(bridge) {
479
757
  this.bridges.push(bridge);
480
758
  bridge.init?.(this);
@@ -488,9 +766,91 @@ var PocketPing = class {
488
766
  getStorage() {
489
767
  return this.storage;
490
768
  }
769
+ // ─────────────────────────────────────────────────────────────────
770
+ // Version Management
771
+ // ─────────────────────────────────────────────────────────────────
772
+ /**
773
+ * Check widget version against configured min/latest versions
774
+ * @param widgetVersion - Version from X-PocketPing-Version header
775
+ * @returns Version check result with status and headers to set
776
+ */
777
+ checkWidgetVersion(widgetVersion) {
778
+ if (!widgetVersion) {
779
+ return {
780
+ status: "ok",
781
+ canContinue: true
782
+ };
783
+ }
784
+ const { minWidgetVersion, latestWidgetVersion } = this.config;
785
+ if (!minWidgetVersion && !latestWidgetVersion) {
786
+ return {
787
+ status: "ok",
788
+ canContinue: true
789
+ };
790
+ }
791
+ let status = "ok";
792
+ let message;
793
+ let canContinue = true;
794
+ if (minWidgetVersion && compareVersions(widgetVersion, minWidgetVersion) < 0) {
795
+ status = "unsupported";
796
+ message = this.config.versionWarningMessage || `Widget version ${widgetVersion} is no longer supported. Minimum version: ${minWidgetVersion}`;
797
+ canContinue = false;
798
+ } else if (latestWidgetVersion && compareVersions(widgetVersion, latestWidgetVersion) < 0) {
799
+ const majorDiff = parseVersion(latestWidgetVersion)[0] - parseVersion(widgetVersion)[0];
800
+ if (majorDiff >= 1) {
801
+ status = "deprecated";
802
+ message = this.config.versionWarningMessage || `Widget version ${widgetVersion} is deprecated. Please update to ${latestWidgetVersion}`;
803
+ } else {
804
+ status = "outdated";
805
+ message = `A newer widget version ${latestWidgetVersion} is available`;
806
+ }
807
+ }
808
+ return {
809
+ status,
810
+ message,
811
+ minVersion: minWidgetVersion,
812
+ latestVersion: latestWidgetVersion,
813
+ canContinue
814
+ };
815
+ }
816
+ /**
817
+ * Set version warning headers on HTTP response
818
+ */
819
+ setVersionHeaders(res, versionCheck) {
820
+ if (versionCheck.status !== "ok") {
821
+ res.setHeader("X-PocketPing-Version-Status", versionCheck.status);
822
+ if (versionCheck.minVersion) {
823
+ res.setHeader("X-PocketPing-Min-Version", versionCheck.minVersion);
824
+ }
825
+ if (versionCheck.latestVersion) {
826
+ res.setHeader("X-PocketPing-Latest-Version", versionCheck.latestVersion);
827
+ }
828
+ if (versionCheck.message) {
829
+ res.setHeader("X-PocketPing-Version-Message", versionCheck.message);
830
+ }
831
+ }
832
+ }
833
+ /**
834
+ * Send version warning via WebSocket to a session
835
+ */
836
+ sendVersionWarning(sessionId, versionCheck) {
837
+ if (versionCheck.status === "ok") return;
838
+ this.broadcastToSession(sessionId, {
839
+ type: "version_warning",
840
+ data: {
841
+ severity: versionCheck.status === "unsupported" ? "error" : versionCheck.status === "deprecated" ? "warning" : "info",
842
+ message: versionCheck.message,
843
+ currentVersion: "unknown",
844
+ // Will be filled by widget
845
+ minVersion: versionCheck.minVersion,
846
+ latestVersion: versionCheck.latestVersion,
847
+ canContinue: versionCheck.canContinue,
848
+ upgradeUrl: this.config.versionUpgradeUrl || "https://docs.pocketping.io/widget/installation"
849
+ }
850
+ });
851
+ }
491
852
  };
492
- // Annotate the CommonJS export names for ESM import in node:
493
- 0 && (module.exports = {
853
+ export {
494
854
  MemoryStorage,
495
855
  PocketPing
496
- });
856
+ };
package/package.json CHANGED
@@ -1,17 +1,28 @@
1
1
  {
2
2
  "name": "@pocketping/sdk-node",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
+ "type": "module",
4
5
  "description": "Node.js SDK for implementing PocketPing protocol",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
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
  ],
11
19
  "scripts": {
20
+ "clean": "rm -rf dist && find src -name '*.js' -o -name '*.js.map' -o -name '*.d.ts' -o -name '*.d.ts.map' | xargs rm -f 2>/dev/null || true",
21
+ "prebuild": "pnpm clean",
12
22
  "build": "tsup src/index.ts --format cjs,esm --dts",
13
23
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
14
- "test": "vitest"
24
+ "test": "vitest run",
25
+ "test:watch": "vitest"
15
26
  },
16
27
  "dependencies": {
17
28
  "ws": "^8.16.0"
@@ -20,7 +31,7 @@
20
31
  "@types/ws": "^8.5.10",
21
32
  "tsup": "^8.0.0",
22
33
  "typescript": "^5.3.0",
23
- "vitest": "^1.2.0"
34
+ "vitest": "^4.0.18"
24
35
  },
25
36
  "peerDependencies": {
26
37
  "express": "^4.18.0 || ^5.0.0"
@@ -43,5 +54,22 @@
43
54
  "type": "git",
44
55
  "url": "https://github.com/Ruwad-io/pocketping.git",
45
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
+ ]
46
74
  }
47
75
  }