@pocketping/sdk-node 1.4.0 → 1.6.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.cjs CHANGED
@@ -1241,8 +1241,38 @@ var WebhookHandler = class {
1241
1241
  this.writeOK(res);
1242
1242
  return;
1243
1243
  }
1244
+ if (update.message_reaction) {
1245
+ const reaction = update.message_reaction;
1246
+ const emoji = reaction.new_reaction?.[0]?.emoji;
1247
+ const topicId = reaction.message_thread_id;
1248
+ if (emoji && emoji.includes("\u{1F5D1}") && topicId && this.config.onOperatorMessageDelete) {
1249
+ const deletedAt = reaction.date ? new Date(reaction.date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
1250
+ await this.config.onOperatorMessageDelete(
1251
+ String(topicId),
1252
+ reaction.message_id,
1253
+ "telegram",
1254
+ deletedAt
1255
+ );
1256
+ }
1257
+ this.writeOK(res);
1258
+ return;
1259
+ }
1244
1260
  if (update.message) {
1245
1261
  const msg = update.message;
1262
+ if (msg.text && /^\/delete(@\w+)?(\s|$)/.test(msg.text)) {
1263
+ const topicId2 = msg.message_thread_id;
1264
+ const replyToId = msg.reply_to_message?.message_id;
1265
+ if (topicId2 && replyToId && this.config.onOperatorMessageDelete) {
1266
+ await this.config.onOperatorMessageDelete(
1267
+ String(topicId2),
1268
+ replyToId,
1269
+ "telegram",
1270
+ (/* @__PURE__ */ new Date()).toISOString()
1271
+ );
1272
+ }
1273
+ this.writeOK(res);
1274
+ return;
1275
+ }
1246
1276
  if (msg.text?.startsWith("/")) {
1247
1277
  this.writeOK(res);
1248
1278
  return;
@@ -1567,10 +1597,140 @@ var WebhookHandler = class {
1567
1597
  }
1568
1598
  };
1569
1599
 
1600
+ // src/errors.ts
1601
+ var PocketPingSetupError = class extends Error {
1602
+ constructor(options) {
1603
+ const message = `[PocketPing] ${options.bridge} configuration error: ${options.missing} is required`;
1604
+ super(message);
1605
+ this.name = "PocketPingSetupError";
1606
+ this.bridge = options.bridge;
1607
+ this.missing = options.missing;
1608
+ this.guide = options.guide;
1609
+ this.docsUrl = options.docsUrl || `https://pocketping.io/docs/${options.bridge.toLowerCase()}`;
1610
+ console.error(this.getFormattedGuide());
1611
+ }
1612
+ getFormattedGuide() {
1613
+ return `
1614
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
1615
+ \u2502 \u26A0\uFE0F ${this.bridge} Setup Required
1616
+ \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
1617
+ \u2502
1618
+ \u2502 Missing: ${this.missing}
1619
+ \u2502
1620
+ ${this.guide.split("\n").map((line) => `\u2502 ${line}`).join("\n")}
1621
+ \u2502
1622
+ \u2502 \u{1F4D6} Full guide: ${this.docsUrl}
1623
+ \u2502
1624
+ \u2502 \u{1F4A1} Quick fix: npx @pocketping/cli init ${this.bridge.toLowerCase()}
1625
+ \u2502
1626
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
1627
+ `;
1628
+ }
1629
+ };
1630
+ var SETUP_GUIDES = {
1631
+ discord: {
1632
+ botToken: `
1633
+ To set up Discord Bot mode:
1634
+
1635
+ 1. Go to https://discord.com/developers/applications
1636
+ 2. Create a new application
1637
+ 3. Go to Bot \u2192 Add Bot \u2192 Reset Token
1638
+ 4. Copy the token and set DISCORD_BOT_TOKEN
1639
+
1640
+ Enable MESSAGE CONTENT INTENT in Bot settings!
1641
+ `,
1642
+ channelId: `
1643
+ To get your Discord Channel ID:
1644
+
1645
+ 1. Enable Developer Mode in Discord:
1646
+ User Settings \u2192 Advanced \u2192 Developer Mode
1647
+ 2. Right-click on your channel \u2192 Copy ID
1648
+ 3. Set DISCORD_CHANNEL_ID in your .env
1649
+
1650
+ Tip: Use a Forum channel for organized threads!
1651
+ `,
1652
+ webhookUrl: `
1653
+ To get a Discord Webhook URL:
1654
+
1655
+ 1. Go to your channel settings
1656
+ 2. Integrations \u2192 Webhooks \u2192 New Webhook
1657
+ 3. Copy the Webhook URL
1658
+
1659
+ Note: Webhooks are send-only. Use Bot mode for full features.
1660
+ `
1661
+ },
1662
+ slack: {
1663
+ botToken: `
1664
+ To set up Slack Bot mode:
1665
+
1666
+ 1. Go to https://api.slack.com/apps
1667
+ 2. Create New App \u2192 From scratch
1668
+ 3. OAuth & Permissions \u2192 Add Bot Token Scopes:
1669
+ - chat:write, channels:read, channels:join
1670
+ - channels:history, groups:history, users:read
1671
+ 4. Install to Workspace \u2192 Copy Bot Token (xoxb-...)
1672
+ `,
1673
+ channelId: `
1674
+ To get your Slack Channel ID:
1675
+
1676
+ 1. Right-click on your channel in Slack
1677
+ 2. View channel details
1678
+ 3. Scroll down to find Channel ID (starts with C or G)
1679
+
1680
+ For private channels: /invite @YourBotName first
1681
+ `,
1682
+ webhookUrl: `
1683
+ To get a Slack Webhook URL:
1684
+
1685
+ 1. Go to https://api.slack.com/apps
1686
+ 2. Incoming Webhooks \u2192 Add New Webhook
1687
+ 3. Select a channel \u2192 Copy Webhook URL
1688
+
1689
+ Note: Webhooks are send-only. Use Bot mode for full features.
1690
+ `
1691
+ },
1692
+ telegram: {
1693
+ botToken: `
1694
+ To create a Telegram Bot:
1695
+
1696
+ 1. Open @BotFather in Telegram
1697
+ 2. Send /newbot
1698
+ 3. Choose a name and username
1699
+ 4. Copy the Bot Token you receive
1700
+
1701
+ Set TELEGRAM_BOT_TOKEN in your .env
1702
+ `,
1703
+ chatId: `
1704
+ To get your Telegram Chat ID:
1705
+
1706
+ 1. Create a group and enable Topics (for forums)
1707
+ 2. Add your bot to the group as admin
1708
+ 3. Add @getidsbot to the group
1709
+ 4. Copy the Chat ID (starts with -100)
1710
+
1711
+ The bot needs "Manage Topics" permission!
1712
+ `
1713
+ }
1714
+ };
1715
+
1570
1716
  // src/bridges/telegram.ts
1571
1717
  var TelegramBridge = class {
1572
1718
  constructor(botToken, chatId, options = {}) {
1573
1719
  this.name = "telegram";
1720
+ if (!botToken) {
1721
+ throw new PocketPingSetupError({
1722
+ bridge: "Telegram",
1723
+ missing: "botToken",
1724
+ guide: SETUP_GUIDES.telegram.botToken
1725
+ });
1726
+ }
1727
+ if (!chatId) {
1728
+ throw new PocketPingSetupError({
1729
+ bridge: "Telegram",
1730
+ missing: "chatId",
1731
+ guide: SETUP_GUIDES.telegram.chatId
1732
+ });
1733
+ }
1574
1734
  this.botToken = botToken;
1575
1735
  this.chatId = chatId;
1576
1736
  this.parseMode = options.parseMode ?? "HTML";
@@ -1739,12 +1899,14 @@ ${dataStr}
1739
1899
  text = `<b>User Identified</b>
1740
1900
  <b>ID:</b> ${this.escapeHtml(identity.id)}
1741
1901
  ` + (identity.name ? `<b>Name:</b> ${this.escapeHtml(identity.name)}
1742
- ` : "") + (identity.email ? `<b>Email:</b> ${this.escapeHtml(identity.email)}` : "");
1902
+ ` : "") + (identity.email ? `<b>Email:</b> ${this.escapeHtml(identity.email)}
1903
+ ` : "") + (session.userPhone ? `<b>Phone:</b> ${this.escapeHtml(session.userPhone)}` : "");
1743
1904
  } else {
1744
1905
  text = `*User Identified*
1745
1906
  *ID:* ${this.escapeMarkdown(identity.id)}
1746
1907
  ` + (identity.name ? `*Name:* ${this.escapeMarkdown(identity.name)}
1747
- ` : "") + (identity.email ? `*Email:* ${this.escapeMarkdown(identity.email)}` : "");
1908
+ ` : "") + (identity.email ? `*Email:* ${this.escapeMarkdown(identity.email)}
1909
+ ` : "") + (session.userPhone ? `*Phone:* ${this.escapeMarkdown(session.userPhone)}` : "");
1748
1910
  }
1749
1911
  try {
1750
1912
  await this.sendMessage(text.trim());
@@ -1842,6 +2004,20 @@ var DiscordBridge = class _DiscordBridge {
1842
2004
  * Create a Discord bridge using a webhook URL
1843
2005
  */
1844
2006
  static webhook(webhookUrl, options = {}) {
2007
+ if (!webhookUrl) {
2008
+ throw new PocketPingSetupError({
2009
+ bridge: "Discord",
2010
+ missing: "webhookUrl",
2011
+ guide: SETUP_GUIDES.discord.webhookUrl
2012
+ });
2013
+ }
2014
+ if (!webhookUrl.startsWith("https://discord.com/api/webhooks/")) {
2015
+ throw new PocketPingSetupError({
2016
+ bridge: "Discord",
2017
+ missing: "valid webhookUrl",
2018
+ guide: "Webhook URL must start with https://discord.com/api/webhooks/\n\n" + SETUP_GUIDES.discord.webhookUrl
2019
+ });
2020
+ }
1845
2021
  return new _DiscordBridge({
1846
2022
  mode: "webhook",
1847
2023
  webhookUrl,
@@ -1853,6 +2029,20 @@ var DiscordBridge = class _DiscordBridge {
1853
2029
  * Create a Discord bridge using a bot token
1854
2030
  */
1855
2031
  static bot(botToken, channelId, options = {}) {
2032
+ if (!botToken) {
2033
+ throw new PocketPingSetupError({
2034
+ bridge: "Discord",
2035
+ missing: "botToken",
2036
+ guide: SETUP_GUIDES.discord.botToken
2037
+ });
2038
+ }
2039
+ if (!channelId) {
2040
+ throw new PocketPingSetupError({
2041
+ bridge: "Discord",
2042
+ missing: "channelId",
2043
+ guide: SETUP_GUIDES.discord.channelId
2044
+ });
2045
+ }
1856
2046
  return new _DiscordBridge({
1857
2047
  mode: "bot",
1858
2048
  botToken,
@@ -2098,6 +2288,9 @@ ${JSON.stringify(event.data, null, 2)}
2098
2288
  if (identity.email) {
2099
2289
  fields.push({ name: "Email", value: identity.email, inline: true });
2100
2290
  }
2291
+ if (session.userPhone) {
2292
+ fields.push({ name: "Phone", value: session.userPhone, inline: true });
2293
+ }
2101
2294
  const embed = {
2102
2295
  title: "User Identified",
2103
2296
  color: 5793266,
@@ -2183,6 +2376,20 @@ var SlackBridge = class _SlackBridge {
2183
2376
  * Create a Slack bridge using a webhook URL
2184
2377
  */
2185
2378
  static webhook(webhookUrl, options = {}) {
2379
+ if (!webhookUrl) {
2380
+ throw new PocketPingSetupError({
2381
+ bridge: "Slack",
2382
+ missing: "webhookUrl",
2383
+ guide: SETUP_GUIDES.slack.webhookUrl
2384
+ });
2385
+ }
2386
+ if (!webhookUrl.startsWith("https://hooks.slack.com/")) {
2387
+ throw new PocketPingSetupError({
2388
+ bridge: "Slack",
2389
+ missing: "valid webhookUrl",
2390
+ guide: "Webhook URL must start with https://hooks.slack.com/\n\n" + SETUP_GUIDES.slack.webhookUrl
2391
+ });
2392
+ }
2186
2393
  return new _SlackBridge({
2187
2394
  mode: "webhook",
2188
2395
  webhookUrl,
@@ -2195,6 +2402,27 @@ var SlackBridge = class _SlackBridge {
2195
2402
  * Create a Slack bridge using a bot token
2196
2403
  */
2197
2404
  static bot(botToken, channelId, options = {}) {
2405
+ if (!botToken) {
2406
+ throw new PocketPingSetupError({
2407
+ bridge: "Slack",
2408
+ missing: "botToken",
2409
+ guide: SETUP_GUIDES.slack.botToken
2410
+ });
2411
+ }
2412
+ if (!botToken.startsWith("xoxb-")) {
2413
+ throw new PocketPingSetupError({
2414
+ bridge: "Slack",
2415
+ missing: "valid botToken",
2416
+ guide: "Bot token must start with xoxb-\n\n" + SETUP_GUIDES.slack.botToken
2417
+ });
2418
+ }
2419
+ if (!channelId) {
2420
+ throw new PocketPingSetupError({
2421
+ bridge: "Slack",
2422
+ missing: "channelId",
2423
+ guide: SETUP_GUIDES.slack.channelId
2424
+ });
2425
+ }
2198
2426
  return new _SlackBridge({
2199
2427
  mode: "bot",
2200
2428
  botToken,
@@ -2486,6 +2714,13 @@ ${identity.name}`
2486
2714
  ${identity.email}`
2487
2715
  });
2488
2716
  }
2717
+ if (session.userPhone) {
2718
+ fields.push({
2719
+ type: "mrkdwn",
2720
+ text: `*Phone:*
2721
+ ${session.userPhone}`
2722
+ });
2723
+ }
2489
2724
  const blocks = [
2490
2725
  {
2491
2726
  type: "header",
package/dist/index.d.cts CHANGED
@@ -207,6 +207,10 @@ interface Session {
207
207
  metadata?: SessionMetadata;
208
208
  /** User identity if identified via PocketPing.identify() */
209
209
  identity?: UserIdentity;
210
+ /** User phone from pre-chat form (E.164 format: +33612345678) */
211
+ userPhone?: string;
212
+ /** User phone country code (ISO: FR, US, etc.) */
213
+ userPhoneCountry?: string;
210
214
  }
211
215
  interface SessionMetadata {
212
216
  url?: string;
package/dist/index.d.ts CHANGED
@@ -207,6 +207,10 @@ interface Session {
207
207
  metadata?: SessionMetadata;
208
208
  /** User identity if identified via PocketPing.identify() */
209
209
  identity?: UserIdentity;
210
+ /** User phone from pre-chat form (E.164 format: +33612345678) */
211
+ userPhone?: string;
212
+ /** User phone country code (ISO: FR, US, etc.) */
213
+ userPhoneCountry?: string;
210
214
  }
211
215
  interface SessionMetadata {
212
216
  url?: string;
package/dist/index.js CHANGED
@@ -1210,8 +1210,38 @@ var WebhookHandler = class {
1210
1210
  this.writeOK(res);
1211
1211
  return;
1212
1212
  }
1213
+ if (update.message_reaction) {
1214
+ const reaction = update.message_reaction;
1215
+ const emoji = reaction.new_reaction?.[0]?.emoji;
1216
+ const topicId = reaction.message_thread_id;
1217
+ if (emoji && emoji.includes("\u{1F5D1}") && topicId && this.config.onOperatorMessageDelete) {
1218
+ const deletedAt = reaction.date ? new Date(reaction.date * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
1219
+ await this.config.onOperatorMessageDelete(
1220
+ String(topicId),
1221
+ reaction.message_id,
1222
+ "telegram",
1223
+ deletedAt
1224
+ );
1225
+ }
1226
+ this.writeOK(res);
1227
+ return;
1228
+ }
1213
1229
  if (update.message) {
1214
1230
  const msg = update.message;
1231
+ if (msg.text && /^\/delete(@\w+)?(\s|$)/.test(msg.text)) {
1232
+ const topicId2 = msg.message_thread_id;
1233
+ const replyToId = msg.reply_to_message?.message_id;
1234
+ if (topicId2 && replyToId && this.config.onOperatorMessageDelete) {
1235
+ await this.config.onOperatorMessageDelete(
1236
+ String(topicId2),
1237
+ replyToId,
1238
+ "telegram",
1239
+ (/* @__PURE__ */ new Date()).toISOString()
1240
+ );
1241
+ }
1242
+ this.writeOK(res);
1243
+ return;
1244
+ }
1215
1245
  if (msg.text?.startsWith("/")) {
1216
1246
  this.writeOK(res);
1217
1247
  return;
@@ -1536,10 +1566,140 @@ var WebhookHandler = class {
1536
1566
  }
1537
1567
  };
1538
1568
 
1569
+ // src/errors.ts
1570
+ var PocketPingSetupError = class extends Error {
1571
+ constructor(options) {
1572
+ const message = `[PocketPing] ${options.bridge} configuration error: ${options.missing} is required`;
1573
+ super(message);
1574
+ this.name = "PocketPingSetupError";
1575
+ this.bridge = options.bridge;
1576
+ this.missing = options.missing;
1577
+ this.guide = options.guide;
1578
+ this.docsUrl = options.docsUrl || `https://pocketping.io/docs/${options.bridge.toLowerCase()}`;
1579
+ console.error(this.getFormattedGuide());
1580
+ }
1581
+ getFormattedGuide() {
1582
+ return `
1583
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
1584
+ \u2502 \u26A0\uFE0F ${this.bridge} Setup Required
1585
+ \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
1586
+ \u2502
1587
+ \u2502 Missing: ${this.missing}
1588
+ \u2502
1589
+ ${this.guide.split("\n").map((line) => `\u2502 ${line}`).join("\n")}
1590
+ \u2502
1591
+ \u2502 \u{1F4D6} Full guide: ${this.docsUrl}
1592
+ \u2502
1593
+ \u2502 \u{1F4A1} Quick fix: npx @pocketping/cli init ${this.bridge.toLowerCase()}
1594
+ \u2502
1595
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
1596
+ `;
1597
+ }
1598
+ };
1599
+ var SETUP_GUIDES = {
1600
+ discord: {
1601
+ botToken: `
1602
+ To set up Discord Bot mode:
1603
+
1604
+ 1. Go to https://discord.com/developers/applications
1605
+ 2. Create a new application
1606
+ 3. Go to Bot \u2192 Add Bot \u2192 Reset Token
1607
+ 4. Copy the token and set DISCORD_BOT_TOKEN
1608
+
1609
+ Enable MESSAGE CONTENT INTENT in Bot settings!
1610
+ `,
1611
+ channelId: `
1612
+ To get your Discord Channel ID:
1613
+
1614
+ 1. Enable Developer Mode in Discord:
1615
+ User Settings \u2192 Advanced \u2192 Developer Mode
1616
+ 2. Right-click on your channel \u2192 Copy ID
1617
+ 3. Set DISCORD_CHANNEL_ID in your .env
1618
+
1619
+ Tip: Use a Forum channel for organized threads!
1620
+ `,
1621
+ webhookUrl: `
1622
+ To get a Discord Webhook URL:
1623
+
1624
+ 1. Go to your channel settings
1625
+ 2. Integrations \u2192 Webhooks \u2192 New Webhook
1626
+ 3. Copy the Webhook URL
1627
+
1628
+ Note: Webhooks are send-only. Use Bot mode for full features.
1629
+ `
1630
+ },
1631
+ slack: {
1632
+ botToken: `
1633
+ To set up Slack Bot mode:
1634
+
1635
+ 1. Go to https://api.slack.com/apps
1636
+ 2. Create New App \u2192 From scratch
1637
+ 3. OAuth & Permissions \u2192 Add Bot Token Scopes:
1638
+ - chat:write, channels:read, channels:join
1639
+ - channels:history, groups:history, users:read
1640
+ 4. Install to Workspace \u2192 Copy Bot Token (xoxb-...)
1641
+ `,
1642
+ channelId: `
1643
+ To get your Slack Channel ID:
1644
+
1645
+ 1. Right-click on your channel in Slack
1646
+ 2. View channel details
1647
+ 3. Scroll down to find Channel ID (starts with C or G)
1648
+
1649
+ For private channels: /invite @YourBotName first
1650
+ `,
1651
+ webhookUrl: `
1652
+ To get a Slack Webhook URL:
1653
+
1654
+ 1. Go to https://api.slack.com/apps
1655
+ 2. Incoming Webhooks \u2192 Add New Webhook
1656
+ 3. Select a channel \u2192 Copy Webhook URL
1657
+
1658
+ Note: Webhooks are send-only. Use Bot mode for full features.
1659
+ `
1660
+ },
1661
+ telegram: {
1662
+ botToken: `
1663
+ To create a Telegram Bot:
1664
+
1665
+ 1. Open @BotFather in Telegram
1666
+ 2. Send /newbot
1667
+ 3. Choose a name and username
1668
+ 4. Copy the Bot Token you receive
1669
+
1670
+ Set TELEGRAM_BOT_TOKEN in your .env
1671
+ `,
1672
+ chatId: `
1673
+ To get your Telegram Chat ID:
1674
+
1675
+ 1. Create a group and enable Topics (for forums)
1676
+ 2. Add your bot to the group as admin
1677
+ 3. Add @getidsbot to the group
1678
+ 4. Copy the Chat ID (starts with -100)
1679
+
1680
+ The bot needs "Manage Topics" permission!
1681
+ `
1682
+ }
1683
+ };
1684
+
1539
1685
  // src/bridges/telegram.ts
1540
1686
  var TelegramBridge = class {
1541
1687
  constructor(botToken, chatId, options = {}) {
1542
1688
  this.name = "telegram";
1689
+ if (!botToken) {
1690
+ throw new PocketPingSetupError({
1691
+ bridge: "Telegram",
1692
+ missing: "botToken",
1693
+ guide: SETUP_GUIDES.telegram.botToken
1694
+ });
1695
+ }
1696
+ if (!chatId) {
1697
+ throw new PocketPingSetupError({
1698
+ bridge: "Telegram",
1699
+ missing: "chatId",
1700
+ guide: SETUP_GUIDES.telegram.chatId
1701
+ });
1702
+ }
1543
1703
  this.botToken = botToken;
1544
1704
  this.chatId = chatId;
1545
1705
  this.parseMode = options.parseMode ?? "HTML";
@@ -1708,12 +1868,14 @@ ${dataStr}
1708
1868
  text = `<b>User Identified</b>
1709
1869
  <b>ID:</b> ${this.escapeHtml(identity.id)}
1710
1870
  ` + (identity.name ? `<b>Name:</b> ${this.escapeHtml(identity.name)}
1711
- ` : "") + (identity.email ? `<b>Email:</b> ${this.escapeHtml(identity.email)}` : "");
1871
+ ` : "") + (identity.email ? `<b>Email:</b> ${this.escapeHtml(identity.email)}
1872
+ ` : "") + (session.userPhone ? `<b>Phone:</b> ${this.escapeHtml(session.userPhone)}` : "");
1712
1873
  } else {
1713
1874
  text = `*User Identified*
1714
1875
  *ID:* ${this.escapeMarkdown(identity.id)}
1715
1876
  ` + (identity.name ? `*Name:* ${this.escapeMarkdown(identity.name)}
1716
- ` : "") + (identity.email ? `*Email:* ${this.escapeMarkdown(identity.email)}` : "");
1877
+ ` : "") + (identity.email ? `*Email:* ${this.escapeMarkdown(identity.email)}
1878
+ ` : "") + (session.userPhone ? `*Phone:* ${this.escapeMarkdown(session.userPhone)}` : "");
1717
1879
  }
1718
1880
  try {
1719
1881
  await this.sendMessage(text.trim());
@@ -1811,6 +1973,20 @@ var DiscordBridge = class _DiscordBridge {
1811
1973
  * Create a Discord bridge using a webhook URL
1812
1974
  */
1813
1975
  static webhook(webhookUrl, options = {}) {
1976
+ if (!webhookUrl) {
1977
+ throw new PocketPingSetupError({
1978
+ bridge: "Discord",
1979
+ missing: "webhookUrl",
1980
+ guide: SETUP_GUIDES.discord.webhookUrl
1981
+ });
1982
+ }
1983
+ if (!webhookUrl.startsWith("https://discord.com/api/webhooks/")) {
1984
+ throw new PocketPingSetupError({
1985
+ bridge: "Discord",
1986
+ missing: "valid webhookUrl",
1987
+ guide: "Webhook URL must start with https://discord.com/api/webhooks/\n\n" + SETUP_GUIDES.discord.webhookUrl
1988
+ });
1989
+ }
1814
1990
  return new _DiscordBridge({
1815
1991
  mode: "webhook",
1816
1992
  webhookUrl,
@@ -1822,6 +1998,20 @@ var DiscordBridge = class _DiscordBridge {
1822
1998
  * Create a Discord bridge using a bot token
1823
1999
  */
1824
2000
  static bot(botToken, channelId, options = {}) {
2001
+ if (!botToken) {
2002
+ throw new PocketPingSetupError({
2003
+ bridge: "Discord",
2004
+ missing: "botToken",
2005
+ guide: SETUP_GUIDES.discord.botToken
2006
+ });
2007
+ }
2008
+ if (!channelId) {
2009
+ throw new PocketPingSetupError({
2010
+ bridge: "Discord",
2011
+ missing: "channelId",
2012
+ guide: SETUP_GUIDES.discord.channelId
2013
+ });
2014
+ }
1825
2015
  return new _DiscordBridge({
1826
2016
  mode: "bot",
1827
2017
  botToken,
@@ -2067,6 +2257,9 @@ ${JSON.stringify(event.data, null, 2)}
2067
2257
  if (identity.email) {
2068
2258
  fields.push({ name: "Email", value: identity.email, inline: true });
2069
2259
  }
2260
+ if (session.userPhone) {
2261
+ fields.push({ name: "Phone", value: session.userPhone, inline: true });
2262
+ }
2070
2263
  const embed = {
2071
2264
  title: "User Identified",
2072
2265
  color: 5793266,
@@ -2152,6 +2345,20 @@ var SlackBridge = class _SlackBridge {
2152
2345
  * Create a Slack bridge using a webhook URL
2153
2346
  */
2154
2347
  static webhook(webhookUrl, options = {}) {
2348
+ if (!webhookUrl) {
2349
+ throw new PocketPingSetupError({
2350
+ bridge: "Slack",
2351
+ missing: "webhookUrl",
2352
+ guide: SETUP_GUIDES.slack.webhookUrl
2353
+ });
2354
+ }
2355
+ if (!webhookUrl.startsWith("https://hooks.slack.com/")) {
2356
+ throw new PocketPingSetupError({
2357
+ bridge: "Slack",
2358
+ missing: "valid webhookUrl",
2359
+ guide: "Webhook URL must start with https://hooks.slack.com/\n\n" + SETUP_GUIDES.slack.webhookUrl
2360
+ });
2361
+ }
2155
2362
  return new _SlackBridge({
2156
2363
  mode: "webhook",
2157
2364
  webhookUrl,
@@ -2164,6 +2371,27 @@ var SlackBridge = class _SlackBridge {
2164
2371
  * Create a Slack bridge using a bot token
2165
2372
  */
2166
2373
  static bot(botToken, channelId, options = {}) {
2374
+ if (!botToken) {
2375
+ throw new PocketPingSetupError({
2376
+ bridge: "Slack",
2377
+ missing: "botToken",
2378
+ guide: SETUP_GUIDES.slack.botToken
2379
+ });
2380
+ }
2381
+ if (!botToken.startsWith("xoxb-")) {
2382
+ throw new PocketPingSetupError({
2383
+ bridge: "Slack",
2384
+ missing: "valid botToken",
2385
+ guide: "Bot token must start with xoxb-\n\n" + SETUP_GUIDES.slack.botToken
2386
+ });
2387
+ }
2388
+ if (!channelId) {
2389
+ throw new PocketPingSetupError({
2390
+ bridge: "Slack",
2391
+ missing: "channelId",
2392
+ guide: SETUP_GUIDES.slack.channelId
2393
+ });
2394
+ }
2167
2395
  return new _SlackBridge({
2168
2396
  mode: "bot",
2169
2397
  botToken,
@@ -2455,6 +2683,13 @@ ${identity.name}`
2455
2683
  ${identity.email}`
2456
2684
  });
2457
2685
  }
2686
+ if (session.userPhone) {
2687
+ fields.push({
2688
+ type: "mrkdwn",
2689
+ text: `*Phone:*
2690
+ ${session.userPhone}`
2691
+ });
2692
+ }
2458
2693
  const blocks = [
2459
2694
  {
2460
2695
  type: "header",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pocketping/sdk-node",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "description": "Node.js SDK for implementing PocketPing protocol",
6
6
  "main": "dist/index.cjs",