@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/core/index.cjs +82 -41
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +82 -41
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +2 -2
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +2 -2
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +2 -2
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.js +2 -2
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +82 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +82 -41
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +32 -0
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.js +32 -0
- package/dist/l1/index.js.map +1 -1
- package/package.json +2 -2
package/dist/core/index.cjs
CHANGED
|
@@ -532,6 +532,33 @@ function waitForConnection() {
|
|
|
532
532
|
connectionCallbacks.push(callback);
|
|
533
533
|
});
|
|
534
534
|
}
|
|
535
|
+
function startPingTimer() {
|
|
536
|
+
stopPingTimer();
|
|
537
|
+
pingTimer = setInterval(() => {
|
|
538
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
539
|
+
try {
|
|
540
|
+
const id = ++requestId;
|
|
541
|
+
ws.send(JSON.stringify({ jsonrpc: "2.0", id, method: "server.ping", params: [] }));
|
|
542
|
+
pending[id] = {
|
|
543
|
+
resolve: () => {
|
|
544
|
+
},
|
|
545
|
+
reject: () => {
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
const timeoutId = setTimeout(() => {
|
|
549
|
+
delete pending[id];
|
|
550
|
+
}, 1e4);
|
|
551
|
+
pending[id].timeoutId = timeoutId;
|
|
552
|
+
} catch {
|
|
553
|
+
}
|
|
554
|
+
}, PING_INTERVAL);
|
|
555
|
+
}
|
|
556
|
+
function stopPingTimer() {
|
|
557
|
+
if (pingTimer) {
|
|
558
|
+
clearInterval(pingTimer);
|
|
559
|
+
pingTimer = null;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
535
562
|
function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
536
563
|
if (isConnected) {
|
|
537
564
|
return Promise.resolve();
|
|
@@ -554,6 +581,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
554
581
|
isConnected = true;
|
|
555
582
|
isConnecting = false;
|
|
556
583
|
reconnectAttempts = 0;
|
|
584
|
+
startPingTimer();
|
|
557
585
|
hasResolved = true;
|
|
558
586
|
resolve();
|
|
559
587
|
connectionCallbacks.forEach((cb) => {
|
|
@@ -565,6 +593,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
565
593
|
ws.onclose = () => {
|
|
566
594
|
isConnected = false;
|
|
567
595
|
isBlockSubscribed = false;
|
|
596
|
+
stopPingTimer();
|
|
568
597
|
Object.values(pending).forEach((req) => {
|
|
569
598
|
if (req.timeoutId) clearTimeout(req.timeoutId);
|
|
570
599
|
req.reject(new Error("WebSocket connection closed"));
|
|
@@ -747,6 +776,7 @@ async function getCurrentBlockHeight() {
|
|
|
747
776
|
}
|
|
748
777
|
}
|
|
749
778
|
function disconnect() {
|
|
779
|
+
stopPingTimer();
|
|
750
780
|
if (ws) {
|
|
751
781
|
intentionalClose = true;
|
|
752
782
|
ws.close();
|
|
@@ -767,7 +797,7 @@ function disconnect() {
|
|
|
767
797
|
blockSubscribers.length = 0;
|
|
768
798
|
lastBlockHeader = null;
|
|
769
799
|
}
|
|
770
|
-
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;
|
|
800
|
+
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;
|
|
771
801
|
var init_network = __esm({
|
|
772
802
|
"l1/network.ts"() {
|
|
773
803
|
"use strict";
|
|
@@ -783,6 +813,7 @@ var init_network = __esm({
|
|
|
783
813
|
reconnectAttempts = 0;
|
|
784
814
|
isBlockSubscribed = false;
|
|
785
815
|
lastBlockHeader = null;
|
|
816
|
+
pingTimer = null;
|
|
786
817
|
pending = {};
|
|
787
818
|
blockSubscribers = [];
|
|
788
819
|
connectionCallbacks = [];
|
|
@@ -791,6 +822,7 @@ var init_network = __esm({
|
|
|
791
822
|
MAX_DELAY = 6e4;
|
|
792
823
|
RPC_TIMEOUT = 3e4;
|
|
793
824
|
CONNECTION_TIMEOUT = 3e4;
|
|
825
|
+
PING_INTERVAL = 3e4;
|
|
794
826
|
}
|
|
795
827
|
});
|
|
796
828
|
|
|
@@ -2514,9 +2546,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
|
|
|
2514
2546
|
if (subId) {
|
|
2515
2547
|
this.nostrClient?.unsubscribe(subId);
|
|
2516
2548
|
}
|
|
2517
|
-
logger.warn("Nostr", `queryEvents timed out after
|
|
2549
|
+
logger.warn("Nostr", `queryEvents timed out after 15s, returning ${events.length} event(s)`, { kinds: filterObj.kinds, limit: filterObj.limit });
|
|
2518
2550
|
resolve(events);
|
|
2519
|
-
},
|
|
2551
|
+
}, 15e3);
|
|
2520
2552
|
const subId = this.nostrClient.subscribe(filter, {
|
|
2521
2553
|
onEvent: (event) => {
|
|
2522
2554
|
events.push({
|
|
@@ -12190,6 +12222,15 @@ var GroupChatModule = class {
|
|
|
12190
12222
|
}
|
|
12191
12223
|
destroy() {
|
|
12192
12224
|
this.destroyConnection();
|
|
12225
|
+
if (this.persistTimer) {
|
|
12226
|
+
clearTimeout(this.persistTimer);
|
|
12227
|
+
this.persistTimer = null;
|
|
12228
|
+
if (this.deps) {
|
|
12229
|
+
this.doPersistAll().catch(
|
|
12230
|
+
(err) => logger.debug("GroupChat", "Persist on destroy failed", err)
|
|
12231
|
+
);
|
|
12232
|
+
}
|
|
12233
|
+
}
|
|
12193
12234
|
this.groups.clear();
|
|
12194
12235
|
this.messages.clear();
|
|
12195
12236
|
this.members.clear();
|
|
@@ -12198,10 +12239,7 @@ var GroupChatModule = class {
|
|
|
12198
12239
|
this.messageHandlers.clear();
|
|
12199
12240
|
this.relayAdminPubkeys = null;
|
|
12200
12241
|
this.relayAdminFetchPromise = null;
|
|
12201
|
-
|
|
12202
|
-
clearTimeout(this.persistTimer);
|
|
12203
|
-
this.persistTimer = null;
|
|
12204
|
-
}
|
|
12242
|
+
this.persistPromise = null;
|
|
12205
12243
|
this.deps = null;
|
|
12206
12244
|
}
|
|
12207
12245
|
destroyConnection() {
|
|
@@ -12326,12 +12364,12 @@ var GroupChatModule = class {
|
|
|
12326
12364
|
if (!this.client) return;
|
|
12327
12365
|
const groupIds = Array.from(this.groups.keys());
|
|
12328
12366
|
if (groupIds.length === 0) return;
|
|
12329
|
-
const
|
|
12367
|
+
const sinceTimestamp = this.getLatestKnownTimestamp(groupIds);
|
|
12330
12368
|
this.trackSubscription(
|
|
12331
12369
|
createNip29Filter({
|
|
12332
12370
|
kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
|
|
12333
12371
|
"#h": groupIds,
|
|
12334
|
-
...
|
|
12372
|
+
...sinceTimestamp ? { since: sinceTimestamp } : {}
|
|
12335
12373
|
}),
|
|
12336
12374
|
{ onEvent: (event) => this.handleGroupEvent(event) }
|
|
12337
12375
|
);
|
|
@@ -12352,12 +12390,12 @@ var GroupChatModule = class {
|
|
|
12352
12390
|
}
|
|
12353
12391
|
subscribeToGroup(groupId) {
|
|
12354
12392
|
if (!this.client) return;
|
|
12355
|
-
const
|
|
12393
|
+
const sinceTimestamp = this.getLatestKnownTimestamp([groupId]);
|
|
12356
12394
|
this.trackSubscription(
|
|
12357
12395
|
createNip29Filter({
|
|
12358
12396
|
kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
|
|
12359
12397
|
"#h": [groupId],
|
|
12360
|
-
...
|
|
12398
|
+
...sinceTimestamp ? { since: sinceTimestamp } : {}
|
|
12361
12399
|
}),
|
|
12362
12400
|
{ onEvent: (event) => this.handleGroupEvent(event) }
|
|
12363
12401
|
);
|
|
@@ -12431,7 +12469,7 @@ var GroupChatModule = class {
|
|
|
12431
12469
|
}
|
|
12432
12470
|
group.updatedAt = event.created_at * 1e3;
|
|
12433
12471
|
this.groups.set(groupId, group);
|
|
12434
|
-
this.
|
|
12472
|
+
this.schedulePersist();
|
|
12435
12473
|
} else if (event.kind === NIP29_KINDS.GROUP_MEMBERS) {
|
|
12436
12474
|
this.updateMembersFromEvent(groupId, event);
|
|
12437
12475
|
} else if (event.kind === NIP29_KINDS.GROUP_ADMINS) {
|
|
@@ -12452,7 +12490,7 @@ var GroupChatModule = class {
|
|
|
12452
12490
|
}
|
|
12453
12491
|
}
|
|
12454
12492
|
this.deps.emitEvent("groupchat:updated", {});
|
|
12455
|
-
this.
|
|
12493
|
+
this.schedulePersist();
|
|
12456
12494
|
} else if (event.kind === NIP29_KINDS.REMOVE_USER) {
|
|
12457
12495
|
if (this.processedEventIds.has(event.id)) return;
|
|
12458
12496
|
const eventTimestampMs = event.created_at * 1e3;
|
|
@@ -12513,7 +12551,7 @@ var GroupChatModule = class {
|
|
|
12513
12551
|
};
|
|
12514
12552
|
this.saveMemberToMemory(member);
|
|
12515
12553
|
}
|
|
12516
|
-
this.
|
|
12554
|
+
this.schedulePersist();
|
|
12517
12555
|
}
|
|
12518
12556
|
updateAdminsFromEvent(groupId, event) {
|
|
12519
12557
|
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
@@ -12533,7 +12571,7 @@ var GroupChatModule = class {
|
|
|
12533
12571
|
});
|
|
12534
12572
|
}
|
|
12535
12573
|
}
|
|
12536
|
-
this.
|
|
12574
|
+
this.schedulePersist();
|
|
12537
12575
|
}
|
|
12538
12576
|
// ===========================================================================
|
|
12539
12577
|
// Group Membership Restoration
|
|
@@ -12544,13 +12582,11 @@ var GroupChatModule = class {
|
|
|
12544
12582
|
if (!myPubkey) return [];
|
|
12545
12583
|
const groupIdsWithMembership = /* @__PURE__ */ new Set();
|
|
12546
12584
|
await this.oneshotSubscription(
|
|
12547
|
-
|
|
12585
|
+
createNip29Filter({ kinds: [NIP29_KINDS.GROUP_MEMBERS], "#p": [myPubkey] }),
|
|
12548
12586
|
{
|
|
12549
12587
|
onEvent: (event) => {
|
|
12550
12588
|
const groupId = this.getGroupIdFromMetadataEvent(event);
|
|
12551
|
-
if (
|
|
12552
|
-
const pTags = event.tags.filter((t) => t[0] === "p");
|
|
12553
|
-
if (pTags.some((tag) => tag[1] === myPubkey)) {
|
|
12589
|
+
if (groupId) {
|
|
12554
12590
|
groupIdsWithMembership.add(groupId);
|
|
12555
12591
|
}
|
|
12556
12592
|
},
|
|
@@ -12562,22 +12598,24 @@ var GroupChatModule = class {
|
|
|
12562
12598
|
);
|
|
12563
12599
|
if (groupIdsWithMembership.size === 0) return [];
|
|
12564
12600
|
const restoredGroups = [];
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12601
|
+
await Promise.all(
|
|
12602
|
+
Array.from(groupIdsWithMembership).map(async (groupId) => {
|
|
12603
|
+
if (this.groups.has(groupId)) return;
|
|
12604
|
+
try {
|
|
12605
|
+
const group = await this.fetchGroupMetadataInternal(groupId);
|
|
12606
|
+
if (group) {
|
|
12607
|
+
this.groups.set(groupId, group);
|
|
12608
|
+
restoredGroups.push(group);
|
|
12609
|
+
await Promise.all([
|
|
12610
|
+
this.fetchAndSaveMembers(groupId),
|
|
12611
|
+
this.fetchMessages(groupId)
|
|
12612
|
+
]);
|
|
12613
|
+
}
|
|
12614
|
+
} catch (error) {
|
|
12615
|
+
logger.warn("GroupChat", "Failed to restore group", groupId, error);
|
|
12576
12616
|
}
|
|
12577
|
-
}
|
|
12578
|
-
|
|
12579
|
-
}
|
|
12580
|
-
}
|
|
12617
|
+
})
|
|
12618
|
+
);
|
|
12581
12619
|
if (restoredGroups.length > 0) {
|
|
12582
12620
|
await this.subscribeToJoinedGroups();
|
|
12583
12621
|
this.deps.emitEvent("groupchat:updated", {});
|
|
@@ -12963,7 +13001,7 @@ var GroupChatModule = class {
|
|
|
12963
13001
|
if (group && (group.unreadCount || 0) > 0) {
|
|
12964
13002
|
group.unreadCount = 0;
|
|
12965
13003
|
this.groups.set(groupId, group);
|
|
12966
|
-
this.
|
|
13004
|
+
this.schedulePersist();
|
|
12967
13005
|
}
|
|
12968
13006
|
}
|
|
12969
13007
|
// ===========================================================================
|
|
@@ -12985,7 +13023,7 @@ var GroupChatModule = class {
|
|
|
12985
13023
|
if (eventId) {
|
|
12986
13024
|
this.removeMemberFromMemory(groupId, userPubkey);
|
|
12987
13025
|
this.deps.emitEvent("groupchat:updated", {});
|
|
12988
|
-
this.
|
|
13026
|
+
this.schedulePersist();
|
|
12989
13027
|
return true;
|
|
12990
13028
|
}
|
|
12991
13029
|
return false;
|
|
@@ -13008,7 +13046,7 @@ var GroupChatModule = class {
|
|
|
13008
13046
|
if (eventId) {
|
|
13009
13047
|
this.deleteMessageFromMemory(groupId, messageId);
|
|
13010
13048
|
this.deps.emitEvent("groupchat:updated", {});
|
|
13011
|
-
this.
|
|
13049
|
+
this.schedulePersist();
|
|
13012
13050
|
return true;
|
|
13013
13051
|
}
|
|
13014
13052
|
return false;
|
|
@@ -13088,7 +13126,7 @@ var GroupChatModule = class {
|
|
|
13088
13126
|
* or 0 if no messages exist. Used to set `since` on subscriptions so the relay
|
|
13089
13127
|
* only sends events we don't already have.
|
|
13090
13128
|
*/
|
|
13091
|
-
|
|
13129
|
+
getLatestKnownTimestamp(groupIds) {
|
|
13092
13130
|
let latest = 0;
|
|
13093
13131
|
for (const gid of groupIds) {
|
|
13094
13132
|
const msgs = this.messages.get(gid);
|
|
@@ -13169,7 +13207,7 @@ var GroupChatModule = class {
|
|
|
13169
13207
|
});
|
|
13170
13208
|
}
|
|
13171
13209
|
}
|
|
13172
|
-
this.
|
|
13210
|
+
this.schedulePersist();
|
|
13173
13211
|
}
|
|
13174
13212
|
async fetchGroupMembersInternal(groupId) {
|
|
13175
13213
|
if (!this.client) return [];
|
|
@@ -13296,8 +13334,11 @@ var GroupChatModule = class {
|
|
|
13296
13334
|
addProcessedEventId(eventId) {
|
|
13297
13335
|
this.processedEventIds.add(eventId);
|
|
13298
13336
|
if (this.processedEventIds.size > 1e4) {
|
|
13299
|
-
|
|
13300
|
-
|
|
13337
|
+
let toDelete = 5e3;
|
|
13338
|
+
for (const id of this.processedEventIds) {
|
|
13339
|
+
if (toDelete-- <= 0) break;
|
|
13340
|
+
this.processedEventIds.delete(id);
|
|
13341
|
+
}
|
|
13301
13342
|
}
|
|
13302
13343
|
}
|
|
13303
13344
|
// ===========================================================================
|