smule.js 1.3.2 → 1.4.1

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/LICENSE CHANGED
File without changes
package/README.md CHANGED
File without changes
package/dist/index.cjs CHANGED
@@ -1364,18 +1364,17 @@ var SmuleUrls;
1364
1364
  var import_xml = require("@xmpp/xml");
1365
1365
  var import_events = __toESM(require("events"), 1);
1366
1366
  var import_jid = require("@xmpp/jid");
1367
+ var import_crypto2 = require("crypto");
1367
1368
  var SmuleLiveChat = class {
1368
1369
  events = new import_events.default();
1369
1370
  state = "closed";
1370
1371
  client;
1371
1372
  jid;
1372
- ongoingIq = false;
1373
- iqHasMore = false;
1374
- lastIqId = "0";
1373
+ iqs = {};
1375
1374
  roomJID = null;
1376
1375
  roomUsers = [];
1377
1376
  chat = { messages: [] };
1378
- constructor(userId, session, host = SmuleUrls.userChat, roomJID) {
1377
+ constructor(userId, session, host = SmuleUrls.cfireChat, roomJID) {
1379
1378
  this.client = (0, import_client.client)({
1380
1379
  service: "xmpp://" + host,
1381
1380
  domain: host,
@@ -1423,6 +1422,9 @@ var SmuleLiveChat = class {
1423
1422
  )
1424
1423
  )
1425
1424
  );
1425
+ this.sendIqQuery("http://jabber.org/protocol/disco#info", (el) => {
1426
+ console.log("reply from disco", el);
1427
+ });
1426
1428
  }
1427
1429
  /**
1428
1430
  * Disconnects the client from the XMPP server.
@@ -1434,83 +1436,41 @@ var SmuleLiveChat = class {
1434
1436
  */
1435
1437
  async disconnect() {
1436
1438
  try {
1439
+ await this.client.send((0, import_client.xml)("presence", { type: "unavailable" }));
1437
1440
  await this.client.stop();
1438
1441
  } catch {
1439
1442
  }
1440
1443
  }
1441
- /**
1442
- * Send a chat state to the server. This is used to
1443
- * signal whether you are currently active or not.
1444
- *
1445
- * active -> You're active
1446
- *
1447
- * composing -> Typing
1448
- *
1449
- * paused -> Just stopped typing
1450
- *
1451
- * inactive -> You're inactive
1452
- *
1453
- * gone -> You're hidden / disconnected / You've left the chat
1454
- *
1455
- * @param state One of `active`, `composing`, `paused`, `inactive`, or `gone`.
1456
- * Default is `active`
1457
- */
1458
- async sendChatState(to, state = "active") {
1459
- if (typeof to != "string" && "accountId" in to) to = this.getJIDFromUserId(to.accountId);
1460
- await this.client.send(
1444
+ sendIq(data, callback, iqType = "get") {
1445
+ const id = (0, import_crypto2.randomUUID)();
1446
+ this.iqs[id] = callback;
1447
+ this.client.send(
1461
1448
  (0, import_client.xml)(
1462
- "message",
1463
- { to: to.toString(), type: "chat" },
1464
- (0, import_client.xml)(
1465
- "chatstate",
1466
- { xmlns: "http://jabber.org/protocol/chatstates" },
1467
- state
1468
- )
1449
+ "iq",
1450
+ { from: this.jid.toString(), to: this.roomJID, type: iqType, id },
1451
+ data
1469
1452
  )
1470
1453
  );
1471
1454
  }
1472
- /**
1473
- * Loads the entire message history
1474
- * @param limit The maximum number of messages to fetch. Default is 50.
1475
- * @remarks This currently recurses until it loads ALL archived messages.
1476
- * This means that it will take a long time to load all messages.
1477
- * @remarks Filtering by a specific JID may not work yet
1478
- */
1479
- async loadMessageHistory(limit = 50, before = null, after = null, jid) {
1480
- this._log("Loading live chat history...");
1481
- this.ongoingIq = true;
1482
- await this.client.send(
1483
- (0, import_client.xml)(
1484
- "iq",
1485
- { from: this.jid.toString(), to: this.roomJID, type: "get", id: "meow" },
1486
- (0, import_client.xml)(
1487
- "query",
1488
- { xmlns: "http://jabber.org/protocol/muc#history" }
1489
- )
1490
- )
1455
+ sendIqQuery(xmlns, callback, iqType = "get") {
1456
+ this.sendIq(
1457
+ (0, import_client.xml)("query", { xmlns }),
1458
+ callback,
1459
+ iqType
1491
1460
  );
1492
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
1493
1461
  }
1494
1462
  /**
1495
- * Send a text message
1496
- * @param jid The JID to send the message to
1463
+ * Send a text message to the livestream
1497
1464
  * @param message The message body
1498
1465
  */
1499
- async sendTextMessage(jid, message) {
1500
- if (typeof jid != "string" && "accountId" in jid) jid = this.getJIDFromUserId(jid.accountId);
1466
+ async sendTextMessage(message) {
1501
1467
  await this.client.send(
1502
1468
  (0, import_client.xml)(
1503
1469
  "message",
1504
- { to: jid.toString(), type: "groupchat" },
1470
+ { to: this.roomJID, type: "groupchat" },
1505
1471
  (0, import_client.xml)("body", {}, message)
1506
1472
  )
1507
1473
  );
1508
- const data = {
1509
- sender: parseInt(this.jid.getLocal()),
1510
- content: message
1511
- };
1512
- this.chat[this.getUserIdFromJID(jid.toString())].messages.push(data);
1513
- this.events.emit("message", data);
1514
1474
  }
1515
1475
  /**
1516
1476
  * Read-only jid to prevent any bugs
@@ -1623,6 +1583,23 @@ var SmuleLiveChat = class {
1623
1583
  this._log("Got host left!", data2);
1624
1584
  this.events.emit("host-left", data2);
1625
1585
  }
1586
+ child = el.getChild("song-listen");
1587
+ if (child) {
1588
+ const data2 = {
1589
+ arrKey: child.getChild("arrangement-key").getText(),
1590
+ hostSessionId: child.getChild("host-session-id").getText()
1591
+ };
1592
+ this._log("Got song listen!", data2);
1593
+ this.events.emit("song-listen", data2);
1594
+ }
1595
+ child = el.getChild("campfire-ended");
1596
+ if (child) {
1597
+ const data2 = {
1598
+ reason: child.getChild("reason").getText()
1599
+ };
1600
+ this._log("Got stop livestream!", data2);
1601
+ this.events.emit("stop-livestream", data2);
1602
+ }
1626
1603
  child = el.getChild("result");
1627
1604
  if (!child) return;
1628
1605
  child = child.getChild("forwarded");
@@ -1646,15 +1623,17 @@ var SmuleLiveChat = class {
1646
1623
  if (child) {
1647
1624
  child = child.getChild("item");
1648
1625
  if (child) {
1649
- if (!el.getAttr("jid")) return;
1650
- const data = {
1651
- user: this.getUserIdFromJID(el.getAttr("jid")),
1652
- role: child.getAttr("role"),
1653
- affiliation: child.getAttr("affiliation")
1654
- };
1655
- this._log("Got presence!", data);
1656
- this.roomUsers.push(data);
1657
- this.events.emit("presence", data);
1626
+ if (!el.getAttr("jid")) {
1627
+ } else {
1628
+ const data = {
1629
+ user: this.getUserIdFromJID(el.getAttr("jid")),
1630
+ role: child.getAttr("role"),
1631
+ affiliation: child.getAttr("affiliation")
1632
+ };
1633
+ this._log("Got presence!", data);
1634
+ this.roomUsers.push(data);
1635
+ this.events.emit("presence", data);
1636
+ }
1658
1637
  }
1659
1638
  }
1660
1639
  }
@@ -1751,22 +1730,11 @@ var SmuleLiveChat = class {
1751
1730
  this.parsePresence(el);
1752
1731
  } else {
1753
1732
  if (el.is("iq")) {
1754
- let child = el.getChild("fin");
1755
- if (child) {
1756
- if (child.getAttr("complete") == "false") {
1757
- this.iqHasMore = true;
1758
- child = child.getChild("set");
1759
- if (child) {
1760
- child = child.getChild("last");
1761
- if (child) {
1762
- this.lastIqId = child.getText();
1763
- }
1764
- }
1765
- } else {
1766
- this.iqHasMore = false;
1767
- }
1733
+ const id = el.getAttr("id");
1734
+ if (id) {
1735
+ this.iqs[id](el);
1736
+ delete this.iqs[id];
1768
1737
  }
1769
- this.ongoingIq = false;
1770
1738
  }
1771
1739
  this._log("Stanza!", el.toString());
1772
1740
  }
@@ -2203,17 +2171,14 @@ var import_client2 = require("@xmpp/client");
2203
2171
  var import_xml2 = require("@xmpp/xml");
2204
2172
  var import_events2 = __toESM(require("events"), 1);
2205
2173
  var import_jid2 = require("@xmpp/jid");
2174
+ var import_crypto3 = require("crypto");
2206
2175
  var SmuleChat = class {
2207
2176
  events = new import_events2.default();
2208
2177
  state = "closed";
2209
2178
  client;
2210
2179
  jid;
2211
- ongoingIq = false;
2212
- iqHasMore = false;
2213
- lastIqId = "0";
2214
- isLive = false;
2180
+ iqs = {};
2215
2181
  roomJID = null;
2216
- roomUsers = [];
2217
2182
  chats = {};
2218
2183
  constructor(userId, session, host = SmuleUrls.userChat, roomJID) {
2219
2184
  this.client = (0, import_client2.client)({
@@ -2224,7 +2189,6 @@ var SmuleChat = class {
2224
2189
  username: userId + "",
2225
2190
  password: session
2226
2191
  });
2227
- this.isLive = host != SmuleUrls.userChat || !!roomJID;
2228
2192
  this.roomJID = roomJID;
2229
2193
  this.client.on("close", (el) => this.onClose(el));
2230
2194
  this.client.on("closing", () => this.onClosing());
@@ -2247,27 +2211,7 @@ var SmuleChat = class {
2247
2211
  async connect() {
2248
2212
  this.jid = await this.client.start();
2249
2213
  this._log("Connected as:", this.jid.getLocal() + "@" + this.jid.getDomain());
2250
- if (!this.isLive && !this.roomJID) {
2251
- this.client.send((0, import_client2.xml)("presence", {}));
2252
- } else {
2253
- this.client.send(
2254
- (0, import_client2.xml)(
2255
- "presence",
2256
- { to: this.roomJID + "/" + this.jid.getLocal() },
2257
- (0, import_client2.xml)(
2258
- "x",
2259
- { xmlns: "http://jabber.org/protocol/muc" },
2260
- (0, import_client2.xml)(
2261
- "password"
2262
- ),
2263
- (0, import_client2.xml)(
2264
- "history",
2265
- { maxstanzas: "1" }
2266
- )
2267
- )
2268
- )
2269
- );
2270
- }
2214
+ this.client.send((0, import_client2.xml)("presence", {}));
2271
2215
  }
2272
2216
  /**
2273
2217
  * Disconnects the client from the XMPP server.
@@ -2279,10 +2223,29 @@ var SmuleChat = class {
2279
2223
  */
2280
2224
  async disconnect() {
2281
2225
  try {
2226
+ await this.client.send((0, import_client2.xml)("presence", { type: "unavailable" }));
2282
2227
  await this.client.stop();
2283
2228
  } catch {
2284
2229
  }
2285
2230
  }
2231
+ sendIq(data, callback, iqType = "get") {
2232
+ const id = (0, import_crypto3.randomUUID)();
2233
+ this.iqs[id] = callback;
2234
+ this.client.send(
2235
+ (0, import_client2.xml)(
2236
+ "iq",
2237
+ { from: this.jid.toString(), to: this.roomJID, type: iqType, id },
2238
+ data
2239
+ )
2240
+ );
2241
+ }
2242
+ sendIqQuery(xmlns, callback, iqType = "get") {
2243
+ this.sendIq(
2244
+ (0, import_client2.xml)("query", { xmlns }),
2245
+ callback,
2246
+ iqType
2247
+ );
2248
+ }
2286
2249
  /**
2287
2250
  * Send a chat state to the server. This is used to
2288
2251
  * signal whether you are currently active or not.
@@ -2322,50 +2285,29 @@ var SmuleChat = class {
2322
2285
  * @remarks Filtering by a specific JID may not work yet
2323
2286
  */
2324
2287
  async loadMessageHistory(limit = 50, before = null, after = null, jid) {
2325
- if (!this.isLive) {
2326
- if (this.ongoingIq) this._log("Waiting for previous iq to finish...");
2327
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2328
- if (jid)
2329
- this._log(`Loading ${limit} messages with ${jid}...`);
2330
- else
2331
- this._log(`Loading ${limit} messages from history...`);
2332
- if (!before && !after && !jid) this.chats = {};
2333
- this.ongoingIq = true;
2334
- await this.client.send(
2335
- (0, import_client2.xml)(
2336
- "iq",
2337
- { type: "set", id: "mam-query" },
2338
- (0, import_client2.xml)(
2339
- "query",
2340
- { xmlns: "urn:xmpp:mam:2" },
2341
- (0, import_client2.xml)(
2342
- "set",
2343
- { xmlns: "http://jabber.org/protocol/rsm" },
2344
- (0, import_client2.xml)("max", {}, limit.toString()),
2345
- before ? (0, import_client2.xml)("before", {}, before.toString()) : null,
2346
- after ? (0, import_client2.xml)("after", {}, after.toString()) : null
2347
- ),
2348
- jid ? (0, import_client2.xml)("with", {}, jid.toString()) : null
2349
- )
2350
- )
2351
- );
2352
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2353
- if (this.iqHasMore) await this.loadMessageHistory(limit, null, this.lastIqId, jid);
2354
- } else {
2355
- this._log("Loading live chat history...");
2356
- this.ongoingIq = true;
2357
- await this.client.send(
2288
+ if (jid)
2289
+ this._log(`Loading ${limit} messages with ${jid}...`);
2290
+ else
2291
+ this._log(`Loading ${limit} messages from history...`);
2292
+ if (!before && !after && !jid) this.chats = {};
2293
+ this.sendIq(
2294
+ (0, import_client2.xml)(
2295
+ "query",
2296
+ { xmlns: "urn:xmpp:mam:2" },
2358
2297
  (0, import_client2.xml)(
2359
- "iq",
2360
- { from: this.jid.toString(), to: this.roomJID, type: "get", id: "meow" },
2361
- (0, import_client2.xml)(
2362
- "query",
2363
- { xmlns: "http://jabber.org/protocol/muc#history" }
2364
- )
2365
- )
2366
- );
2367
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2368
- }
2298
+ "set",
2299
+ { xmlns: "http://jabber.org/protocol/rsm" },
2300
+ (0, import_client2.xml)("max", {}, limit.toString()),
2301
+ before ? (0, import_client2.xml)("before", {}, before.toString()) : null,
2302
+ after ? (0, import_client2.xml)("after", {}, after.toString()) : null
2303
+ ),
2304
+ jid ? (0, import_client2.xml)("with", {}, jid.toString()) : null
2305
+ ),
2306
+ (el) => {
2307
+ this._log("Finished loading history!", el.toString());
2308
+ },
2309
+ "set"
2310
+ );
2369
2311
  }
2370
2312
  /**
2371
2313
  * Send a text message
@@ -2377,16 +2319,10 @@ var SmuleChat = class {
2377
2319
  await this.client.send(
2378
2320
  (0, import_client2.xml)(
2379
2321
  "message",
2380
- { to: jid.toString(), type: this.isLive ? "groupchat" : "chat" },
2322
+ { to: jid.toString(), type: "chat" },
2381
2323
  (0, import_client2.xml)("body", {}, message)
2382
2324
  )
2383
2325
  );
2384
- let data = {
2385
- sender: parseInt(this.jid.getLocal()),
2386
- content: message
2387
- };
2388
- this.chats[this.getUserIdFromJID(jid.toString())].messages.push(data);
2389
- this.events.emit("message", data);
2390
2326
  }
2391
2327
  /**
2392
2328
  * Send a performance / recording
@@ -2426,25 +2362,6 @@ var SmuleChat = class {
2426
2362
  )
2427
2363
  );
2428
2364
  }
2429
- //TODO - Most definitely not required
2430
- async archiveMessage(jid, message) {
2431
- if (typeof jid != "string" && "accountId" in jid) jid = this.getJIDFromUserId(jid.accountId);
2432
- await this.client.send(
2433
- (0, import_client2.xml)(
2434
- "iq",
2435
- { type: "set" },
2436
- (0, import_client2.xml)(
2437
- "archive",
2438
- { xmlns: "urn:xmpp:mam:2" },
2439
- (0, import_client2.xml)(
2440
- "item",
2441
- { with: jid, id: Math.random().toString(16).substring(2, 8) },
2442
- (0, import_client2.xml)("body", {}, message)
2443
- )
2444
- )
2445
- )
2446
- );
2447
- }
2448
2365
  /**
2449
2366
  * Read-only jid to prevent any bugs
2450
2367
  * @returns user's JID
@@ -2468,7 +2385,6 @@ var SmuleChat = class {
2468
2385
  */
2469
2386
  getJIDFromUserId(userId) {
2470
2387
  if (typeof userId != "string" && typeof userId != "number" && "accountId" in userId) userId = userId.accountId;
2471
- if (this.isLive) return this.roomJID + "/" + userId;
2472
2388
  return userId + "@" + this.jid.getDomain();
2473
2389
  }
2474
2390
  //* Processes all message-like elements
@@ -2493,7 +2409,6 @@ var SmuleChat = class {
2493
2409
  }
2494
2410
  child = el.getChild("body");
2495
2411
  const perfChild = el.getChild("performance");
2496
- const perfStartChild = el.getChild("performance-start");
2497
2412
  if (child && (child.getText().trim().length > 0 || perfChild)) {
2498
2413
  this._log("Got message!", child.getText());
2499
2414
  let performanceKey2 = void 0;
@@ -2524,7 +2439,8 @@ var SmuleChat = class {
2524
2439
  content: child.getText(),
2525
2440
  sender: this.getUserIdFromJID(child.parent.getAttr("from")),
2526
2441
  id: child.parent.getAttr("id"),
2527
- performanceKey
2442
+ performanceKey,
2443
+ systemMessage: !!child.parent.getChild("smule-system-msg")
2528
2444
  };
2529
2445
  let chat = this.jid.getLocal().includes(data.sender + "") ? this.getUserIdFromJID(child.parent.getAttr("to")) : data.sender;
2530
2446
  this.events.emit("history", data);
@@ -2533,25 +2449,6 @@ var SmuleChat = class {
2533
2449
  }
2534
2450
  parsePresence(el) {
2535
2451
  if (el.children.length < 1) return;
2536
- if (this.isLive) {
2537
- let child = el.getChildByAttr("xmlns", "http://jabber.org/protocol/muc#user");
2538
- if (child) {
2539
- child = child.getChild("item");
2540
- if (child) {
2541
- if (!el.getAttr("jid")) return;
2542
- let user = this.getUserIdFromJID(el.getAttr("jid"));
2543
- let role = child.getAttr("role");
2544
- let affiliation = child.getAttr("affiliation");
2545
- let data = {
2546
- user,
2547
- role,
2548
- affiliation
2549
- };
2550
- this.roomUsers.push(data);
2551
- this.events.emit("presence", data);
2552
- }
2553
- }
2554
- }
2555
2452
  }
2556
2453
  /**
2557
2454
  * Fetches the chats currently loaded
@@ -2569,9 +2466,6 @@ var SmuleChat = class {
2569
2466
  if (!(user in this.chats)) this.chats[user] = { messages: [] };
2570
2467
  return this.chats[user];
2571
2468
  }
2572
- fetchUsers() {
2573
- return this.roomUsers;
2574
- }
2575
2469
  //#region Internal events
2576
2470
  onClose(el) {
2577
2471
  this._log("Closed!:", el);
@@ -2655,22 +2549,11 @@ var SmuleChat = class {
2655
2549
  this.parsePresence(el);
2656
2550
  } else {
2657
2551
  if (el.is("iq")) {
2658
- let child = el.getChild("fin");
2659
- if (child) {
2660
- if (child.getAttr("complete") == "false") {
2661
- this.iqHasMore = true;
2662
- child = child.getChild("set");
2663
- if (child) {
2664
- child = child.getChild("last");
2665
- if (child) {
2666
- this.lastIqId = child.getText();
2667
- }
2668
- }
2669
- } else {
2670
- this.iqHasMore = false;
2671
- }
2552
+ const id = el.getAttr("id");
2553
+ if (id) {
2554
+ this.iqs[id](el);
2555
+ delete this.iqs[id];
2672
2556
  }
2673
- this.ongoingIq = false;
2674
2557
  }
2675
2558
  this._log("Stanza!", el.toString());
2676
2559
  }
@@ -2678,13 +2561,13 @@ var SmuleChat = class {
2678
2561
  //#endregion Internal events
2679
2562
  //#region Logging
2680
2563
  _log(...args) {
2681
- console.log(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2564
+ console.log("[SmuleChat]", ...args);
2682
2565
  }
2683
2566
  _warn(...args) {
2684
- console.warn(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2567
+ console.warn("[SmuleChat]", ...args);
2685
2568
  }
2686
2569
  _error(...args) {
2687
- console.error(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2570
+ console.error("[SmuleChat]", ...args);
2688
2571
  }
2689
2572
  //#endregion Logging
2690
2573
  };
@@ -2693,7 +2576,7 @@ var SmuleChat = class {
2693
2576
  var import_fs = require("fs");
2694
2577
  var crypto = __toESM(require("crypto"), 1);
2695
2578
  var import_jid3 = require("@xmpp/jid");
2696
- var APP_VERSION = "12.0.9";
2579
+ var APP_VERSION = "12.6.9";
2697
2580
  var SmuleDigest;
2698
2581
  ((SmuleDigest2) => {
2699
2582
  const SALT = `c2250918de500e32c37842f2d25d4d8210992a0ae96a7f36c4c9703cc675d02b92968bc4fa7feada`;
@@ -3237,13 +3120,37 @@ var Smule = class {
3237
3120
  * Creates a new spark chat
3238
3121
  * @param address The JID address of the chat partner
3239
3122
  * @param type Whether the JID address is an individual or a group
3240
- * @returns idk
3241
3123
  */
3242
3124
  create: async (address, type = "ACCT") => {
3243
3125
  const req = await this.internal._createRequest(SmuleUrls.SparkChatUpdate, { add: [{ name: address, type }], remove: [] });
3126
+ this.internal._handleNon200(req);
3127
+ },
3128
+ /**
3129
+ * Deletes an existing spark chat
3130
+ * @param address The JID address of the chat partner
3131
+ * @param type Whether the JID address is an individual or a group
3132
+ */
3133
+ delete: async (address, type = "ACCT") => {
3134
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatUpdate, { remove: [{ name: address, type }], add: [] });
3135
+ this.internal._handleNon200(req);
3136
+ },
3137
+ /**
3138
+ * Fetches your existing chats
3139
+ * @param type Whether an individual or a group
3140
+ * @returns Your inbox and your message requests
3141
+ */
3142
+ fetchInboxes: async (type = "ACCT") => {
3143
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatList, { type, limit: 200 });
3244
3144
  if (!this.internal._handleNon200(req)) return;
3245
3145
  return this.internal._getResponseData(req);
3246
3146
  },
3147
+ /**
3148
+ * Marks you as offline to your chats
3149
+ */
3150
+ markOffline: async () => {
3151
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatOffline, {});
3152
+ this.internal._handleNon200(req);
3153
+ },
3247
3154
  /**
3248
3155
  * Creates a connection to the XMPP chat server
3249
3156
  */
@@ -4414,9 +4321,9 @@ var Smule = class {
4414
4321
  * @param to The user to send the message to
4415
4322
  * @param message The message body
4416
4323
  */
4417
- sendTextMessage: async (to, message) => {
4324
+ sendTextMessage: async (message) => {
4418
4325
  if (!this.liveChatSession) return;
4419
- await this.liveChatSession.sendTextMessage(to, message);
4326
+ await this.liveChatSession.sendTextMessage(message);
4420
4327
  },
4421
4328
  /**
4422
4329
  * Fetch all loaded chats
@@ -4429,27 +4336,47 @@ var Smule = class {
4429
4336
  fetchUsers: () => {
4430
4337
  if (!this.liveChatSession) return;
4431
4338
  return this.liveChatSession.fetchUsers();
4432
- },
4433
- /**
4434
- * Loads the entire message history
4435
- * @param limit How many messages
4436
- * @param before Messages before this
4437
- * @param after Messages after this
4438
- * @param user The chat partner
4439
- *
4440
- * @remarks This currently recurses until it loads ALL archived messages.
4441
- * This means that it will take a long time to load all messages.
4442
- * @remarks Filtering by a specific user may not work yet
4443
- */
4444
- loadMessageHistory: async (limit = 50, before = null, after = null, user) => {
4445
- if (!this.liveChatSession) return;
4446
- await this.liveChatSession.loadMessageHistory(limit, before, after, user);
4447
4339
  }
4448
4340
  },
4341
+ /**
4342
+ * Fetches ("syncs") a livestream (campfire) so you can connect to it
4343
+ *
4344
+ * @param campfireId The campfire's id
4345
+ * @returns Data regarding the campfire and the streaming details
4346
+ */
4449
4347
  fetch: async (campfireId) => {
4450
4348
  const req = await this.internal._createRequest(SmuleUrls.CfireSync, { campfireId });
4451
4349
  if (!this.internal._handleNon200(req)) return;
4452
4350
  return this.internal._getResponseData(req);
4351
+ },
4352
+ /**
4353
+ * Fetches gifts that have been sent to a live
4354
+ *
4355
+ * @param campfireId The campfire's id
4356
+ * @param cursor The starting point
4357
+ * @param limit How many results
4358
+ * @returns A list of gifts data
4359
+ */
4360
+ fetchRecentGifts: async (campfireId, cursor = "start", limit = 10) => {
4361
+ const req = await this.internal._createRequest(SmuleUrls.GiftRecentTransactions, { campfireId, cursor, limit, animationVersion: "V2", extraGiftTypes: ["SYSTEM"], previewVersion: "PNG", type: "CFIRE" });
4362
+ if (!this.internal._handleNon200(req)) return;
4363
+ return this.internal._getResponseData(req);
4364
+ },
4365
+ /**
4366
+ * Sign up as available to sing
4367
+ * @param campfireId The livestream's id
4368
+ */
4369
+ joinToSing: async (campfireId) => {
4370
+ const req = await this.internal._createRequest(SmuleUrls.CfireSignupAdd, { campfireId, message: "I'm available to sing" });
4371
+ this.internal._handleNon200(req);
4372
+ },
4373
+ /**
4374
+ * Revoke your availability to sing
4375
+ * @param campfireId The livestream's id
4376
+ */
4377
+ revokeJoinToSing: async (campfireId) => {
4378
+ const req = await this.internal._createRequest(SmuleUrls.CfireSignupRemove, { campfireId });
4379
+ this.internal._handleNon200(req);
4453
4380
  }
4454
4381
  };
4455
4382
  groups = {