@unicitylabs/sphere-sdk 0.6.10-dev.4 → 0.6.10-dev.5

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.d.cts CHANGED
@@ -3740,7 +3740,7 @@ declare class GroupChatModule {
3740
3740
  * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
3741
3741
  * only sends events we don't already have.
3742
3742
  */
3743
- private getLatestMessageTimestamp;
3743
+ private getLatestKnownTimestamp;
3744
3744
  private fetchRelayAdmins;
3745
3745
  private doFetchRelayAdmins;
3746
3746
  private fetchGroupMetadataInternal;
package/dist/index.d.ts CHANGED
@@ -3740,7 +3740,7 @@ declare class GroupChatModule {
3740
3740
  * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
3741
3741
  * only sends events we don't already have.
3742
3742
  */
3743
- private getLatestMessageTimestamp;
3743
+ private getLatestKnownTimestamp;
3744
3744
  private fetchRelayAdmins;
3745
3745
  private doFetchRelayAdmins;
3746
3746
  private fetchGroupMetadataInternal;
package/dist/index.js CHANGED
@@ -542,6 +542,33 @@ function waitForConnection() {
542
542
  connectionCallbacks.push(callback);
543
543
  });
544
544
  }
545
+ function startPingTimer() {
546
+ stopPingTimer();
547
+ pingTimer = setInterval(() => {
548
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
549
+ try {
550
+ const id = ++requestId;
551
+ ws.send(JSON.stringify({ jsonrpc: "2.0", id, method: "server.ping", params: [] }));
552
+ pending[id] = {
553
+ resolve: () => {
554
+ },
555
+ reject: () => {
556
+ }
557
+ };
558
+ const timeoutId = setTimeout(() => {
559
+ delete pending[id];
560
+ }, 1e4);
561
+ pending[id].timeoutId = timeoutId;
562
+ } catch {
563
+ }
564
+ }, PING_INTERVAL);
565
+ }
566
+ function stopPingTimer() {
567
+ if (pingTimer) {
568
+ clearInterval(pingTimer);
569
+ pingTimer = null;
570
+ }
571
+ }
545
572
  function connect(endpoint = DEFAULT_ENDPOINT) {
546
573
  if (isConnected) {
547
574
  return Promise.resolve();
@@ -564,6 +591,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
564
591
  isConnected = true;
565
592
  isConnecting = false;
566
593
  reconnectAttempts = 0;
594
+ startPingTimer();
567
595
  hasResolved = true;
568
596
  resolve();
569
597
  connectionCallbacks.forEach((cb) => {
@@ -575,6 +603,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
575
603
  ws.onclose = () => {
576
604
  isConnected = false;
577
605
  isBlockSubscribed = false;
606
+ stopPingTimer();
578
607
  Object.values(pending).forEach((req) => {
579
608
  if (req.timeoutId) clearTimeout(req.timeoutId);
580
609
  req.reject(new Error("WebSocket connection closed"));
@@ -757,6 +786,7 @@ async function getCurrentBlockHeight() {
757
786
  }
758
787
  }
759
788
  function disconnect() {
789
+ stopPingTimer();
760
790
  if (ws) {
761
791
  intentionalClose = true;
762
792
  ws.close();
@@ -777,7 +807,7 @@ function disconnect() {
777
807
  blockSubscribers.length = 0;
778
808
  lastBlockHeader = null;
779
809
  }
780
- var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose, reconnectAttempts, isBlockSubscribed, lastBlockHeader, pending, blockSubscribers, connectionCallbacks, MAX_RECONNECT_ATTEMPTS, BASE_DELAY, MAX_DELAY, RPC_TIMEOUT, CONNECTION_TIMEOUT;
810
+ var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose, reconnectAttempts, isBlockSubscribed, lastBlockHeader, pingTimer, pending, blockSubscribers, connectionCallbacks, MAX_RECONNECT_ATTEMPTS, BASE_DELAY, MAX_DELAY, RPC_TIMEOUT, CONNECTION_TIMEOUT, PING_INTERVAL;
781
811
  var init_network = __esm({
782
812
  "l1/network.ts"() {
783
813
  "use strict";
@@ -793,6 +823,7 @@ var init_network = __esm({
793
823
  reconnectAttempts = 0;
794
824
  isBlockSubscribed = false;
795
825
  lastBlockHeader = null;
826
+ pingTimer = null;
796
827
  pending = {};
797
828
  blockSubscribers = [];
798
829
  connectionCallbacks = [];
@@ -801,6 +832,7 @@ var init_network = __esm({
801
832
  MAX_DELAY = 6e4;
802
833
  RPC_TIMEOUT = 3e4;
803
834
  CONNECTION_TIMEOUT = 3e4;
835
+ PING_INTERVAL = 3e4;
804
836
  }
805
837
  });
806
838
 
@@ -2461,9 +2493,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
2461
2493
  if (subId) {
2462
2494
  this.nostrClient?.unsubscribe(subId);
2463
2495
  }
2464
- logger.warn("Nostr", `queryEvents timed out after 5s, returning ${events.length} event(s)`, { kinds: filterObj.kinds, limit: filterObj.limit });
2496
+ logger.warn("Nostr", `queryEvents timed out after 15s, returning ${events.length} event(s)`, { kinds: filterObj.kinds, limit: filterObj.limit });
2465
2497
  resolve(events);
2466
- }, 5e3);
2498
+ }, 15e3);
2467
2499
  const subId = this.nostrClient.subscribe(filter, {
2468
2500
  onEvent: (event) => {
2469
2501
  events.push({
@@ -12383,6 +12415,15 @@ var GroupChatModule = class {
12383
12415
  }
12384
12416
  destroy() {
12385
12417
  this.destroyConnection();
12418
+ if (this.persistTimer) {
12419
+ clearTimeout(this.persistTimer);
12420
+ this.persistTimer = null;
12421
+ if (this.deps) {
12422
+ this.doPersistAll().catch(
12423
+ (err) => logger.debug("GroupChat", "Persist on destroy failed", err)
12424
+ );
12425
+ }
12426
+ }
12386
12427
  this.groups.clear();
12387
12428
  this.messages.clear();
12388
12429
  this.members.clear();
@@ -12391,10 +12432,7 @@ var GroupChatModule = class {
12391
12432
  this.messageHandlers.clear();
12392
12433
  this.relayAdminPubkeys = null;
12393
12434
  this.relayAdminFetchPromise = null;
12394
- if (this.persistTimer) {
12395
- clearTimeout(this.persistTimer);
12396
- this.persistTimer = null;
12397
- }
12435
+ this.persistPromise = null;
12398
12436
  this.deps = null;
12399
12437
  }
12400
12438
  destroyConnection() {
@@ -12519,12 +12557,12 @@ var GroupChatModule = class {
12519
12557
  if (!this.client) return;
12520
12558
  const groupIds = Array.from(this.groups.keys());
12521
12559
  if (groupIds.length === 0) return;
12522
- const latestTimestamp = this.getLatestMessageTimestamp(groupIds);
12560
+ const sinceTimestamp = this.getLatestKnownTimestamp(groupIds);
12523
12561
  this.trackSubscription(
12524
12562
  createNip29Filter({
12525
12563
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
12526
12564
  "#h": groupIds,
12527
- ...latestTimestamp ? { since: latestTimestamp } : {}
12565
+ ...sinceTimestamp ? { since: sinceTimestamp } : {}
12528
12566
  }),
12529
12567
  { onEvent: (event) => this.handleGroupEvent(event) }
12530
12568
  );
@@ -12545,12 +12583,12 @@ var GroupChatModule = class {
12545
12583
  }
12546
12584
  subscribeToGroup(groupId) {
12547
12585
  if (!this.client) return;
12548
- const latestTimestamp = this.getLatestMessageTimestamp([groupId]);
12586
+ const sinceTimestamp = this.getLatestKnownTimestamp([groupId]);
12549
12587
  this.trackSubscription(
12550
12588
  createNip29Filter({
12551
12589
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
12552
12590
  "#h": [groupId],
12553
- ...latestTimestamp ? { since: latestTimestamp } : {}
12591
+ ...sinceTimestamp ? { since: sinceTimestamp } : {}
12554
12592
  }),
12555
12593
  { onEvent: (event) => this.handleGroupEvent(event) }
12556
12594
  );
@@ -12624,7 +12662,7 @@ var GroupChatModule = class {
12624
12662
  }
12625
12663
  group.updatedAt = event.created_at * 1e3;
12626
12664
  this.groups.set(groupId, group);
12627
- this.persistGroups();
12665
+ this.schedulePersist();
12628
12666
  } else if (event.kind === NIP29_KINDS.GROUP_MEMBERS) {
12629
12667
  this.updateMembersFromEvent(groupId, event);
12630
12668
  } else if (event.kind === NIP29_KINDS.GROUP_ADMINS) {
@@ -12645,7 +12683,7 @@ var GroupChatModule = class {
12645
12683
  }
12646
12684
  }
12647
12685
  this.deps.emitEvent("groupchat:updated", {});
12648
- this.persistMessages();
12686
+ this.schedulePersist();
12649
12687
  } else if (event.kind === NIP29_KINDS.REMOVE_USER) {
12650
12688
  if (this.processedEventIds.has(event.id)) return;
12651
12689
  const eventTimestampMs = event.created_at * 1e3;
@@ -12706,7 +12744,7 @@ var GroupChatModule = class {
12706
12744
  };
12707
12745
  this.saveMemberToMemory(member);
12708
12746
  }
12709
- this.persistMembers();
12747
+ this.schedulePersist();
12710
12748
  }
12711
12749
  updateAdminsFromEvent(groupId, event) {
12712
12750
  const pTags = event.tags.filter((t) => t[0] === "p");
@@ -12726,7 +12764,7 @@ var GroupChatModule = class {
12726
12764
  });
12727
12765
  }
12728
12766
  }
12729
- this.persistMembers();
12767
+ this.schedulePersist();
12730
12768
  }
12731
12769
  // ===========================================================================
12732
12770
  // Group Membership Restoration
@@ -12737,13 +12775,11 @@ var GroupChatModule = class {
12737
12775
  if (!myPubkey) return [];
12738
12776
  const groupIdsWithMembership = /* @__PURE__ */ new Set();
12739
12777
  await this.oneshotSubscription(
12740
- new Filter3({ kinds: [NIP29_KINDS.GROUP_MEMBERS] }),
12778
+ createNip29Filter({ kinds: [NIP29_KINDS.GROUP_MEMBERS], "#p": [myPubkey] }),
12741
12779
  {
12742
12780
  onEvent: (event) => {
12743
12781
  const groupId = this.getGroupIdFromMetadataEvent(event);
12744
- if (!groupId) return;
12745
- const pTags = event.tags.filter((t) => t[0] === "p");
12746
- if (pTags.some((tag) => tag[1] === myPubkey)) {
12782
+ if (groupId) {
12747
12783
  groupIdsWithMembership.add(groupId);
12748
12784
  }
12749
12785
  },
@@ -12755,22 +12791,24 @@ var GroupChatModule = class {
12755
12791
  );
12756
12792
  if (groupIdsWithMembership.size === 0) return [];
12757
12793
  const restoredGroups = [];
12758
- for (const groupId of groupIdsWithMembership) {
12759
- if (this.groups.has(groupId)) continue;
12760
- try {
12761
- const group = await this.fetchGroupMetadataInternal(groupId);
12762
- if (group) {
12763
- this.groups.set(groupId, group);
12764
- restoredGroups.push(group);
12765
- await Promise.all([
12766
- this.fetchAndSaveMembers(groupId),
12767
- this.fetchMessages(groupId)
12768
- ]);
12794
+ await Promise.all(
12795
+ Array.from(groupIdsWithMembership).map(async (groupId) => {
12796
+ if (this.groups.has(groupId)) return;
12797
+ try {
12798
+ const group = await this.fetchGroupMetadataInternal(groupId);
12799
+ if (group) {
12800
+ this.groups.set(groupId, group);
12801
+ restoredGroups.push(group);
12802
+ await Promise.all([
12803
+ this.fetchAndSaveMembers(groupId),
12804
+ this.fetchMessages(groupId)
12805
+ ]);
12806
+ }
12807
+ } catch (error) {
12808
+ logger.warn("GroupChat", "Failed to restore group", groupId, error);
12769
12809
  }
12770
- } catch (error) {
12771
- logger.warn("GroupChat", "Failed to restore group", groupId, error);
12772
- }
12773
- }
12810
+ })
12811
+ );
12774
12812
  if (restoredGroups.length > 0) {
12775
12813
  await this.subscribeToJoinedGroups();
12776
12814
  this.deps.emitEvent("groupchat:updated", {});
@@ -13156,7 +13194,7 @@ var GroupChatModule = class {
13156
13194
  if (group && (group.unreadCount || 0) > 0) {
13157
13195
  group.unreadCount = 0;
13158
13196
  this.groups.set(groupId, group);
13159
- this.persistGroups();
13197
+ this.schedulePersist();
13160
13198
  }
13161
13199
  }
13162
13200
  // ===========================================================================
@@ -13178,7 +13216,7 @@ var GroupChatModule = class {
13178
13216
  if (eventId) {
13179
13217
  this.removeMemberFromMemory(groupId, userPubkey);
13180
13218
  this.deps.emitEvent("groupchat:updated", {});
13181
- this.persistMembers();
13219
+ this.schedulePersist();
13182
13220
  return true;
13183
13221
  }
13184
13222
  return false;
@@ -13201,7 +13239,7 @@ var GroupChatModule = class {
13201
13239
  if (eventId) {
13202
13240
  this.deleteMessageFromMemory(groupId, messageId);
13203
13241
  this.deps.emitEvent("groupchat:updated", {});
13204
- this.persistMessages();
13242
+ this.schedulePersist();
13205
13243
  return true;
13206
13244
  }
13207
13245
  return false;
@@ -13281,7 +13319,7 @@ var GroupChatModule = class {
13281
13319
  * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
13282
13320
  * only sends events we don't already have.
13283
13321
  */
13284
- getLatestMessageTimestamp(groupIds) {
13322
+ getLatestKnownTimestamp(groupIds) {
13285
13323
  let latest = 0;
13286
13324
  for (const gid of groupIds) {
13287
13325
  const msgs = this.messages.get(gid);
@@ -13362,7 +13400,7 @@ var GroupChatModule = class {
13362
13400
  });
13363
13401
  }
13364
13402
  }
13365
- this.persistMembers();
13403
+ this.schedulePersist();
13366
13404
  }
13367
13405
  async fetchGroupMembersInternal(groupId) {
13368
13406
  if (!this.client) return [];
@@ -13489,8 +13527,11 @@ var GroupChatModule = class {
13489
13527
  addProcessedEventId(eventId) {
13490
13528
  this.processedEventIds.add(eventId);
13491
13529
  if (this.processedEventIds.size > 1e4) {
13492
- const arr = Array.from(this.processedEventIds);
13493
- this.processedEventIds = new Set(arr.slice(arr.length - 1e4));
13530
+ let toDelete = 5e3;
13531
+ for (const id of this.processedEventIds) {
13532
+ if (toDelete-- <= 0) break;
13533
+ this.processedEventIds.delete(id);
13534
+ }
13494
13535
  }
13495
13536
  }
13496
13537
  // ===========================================================================