@unicitylabs/sphere-sdk 0.2.5 → 0.3.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/README.md +166 -8
- package/dist/core/index.cjs +2143 -795
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +248 -46
- package/dist/core/index.d.ts +248 -46
- package/dist/core/index.js +2144 -792
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +58 -111
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +58 -111
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +33 -85
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js +33 -85
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +58 -116
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +23 -20
- package/dist/impl/nodejs/index.d.ts +23 -20
- package/dist/impl/nodejs/index.js +58 -116
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +5647 -4329
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +304 -50
- package/dist/index.d.ts +304 -50
- package/dist/index.js +5634 -4318
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
|
@@ -84,7 +84,17 @@ var STORAGE_KEYS_GLOBAL = {
|
|
|
84
84
|
/** Active addresses registry (JSON: TrackedAddressesStorage) */
|
|
85
85
|
TRACKED_ADDRESSES: "tracked_addresses",
|
|
86
86
|
/** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
|
|
87
|
-
LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
|
|
87
|
+
LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
|
|
88
|
+
/** Group chat: joined groups */
|
|
89
|
+
GROUP_CHAT_GROUPS: "group_chat_groups",
|
|
90
|
+
/** Group chat: messages */
|
|
91
|
+
GROUP_CHAT_MESSAGES: "group_chat_messages",
|
|
92
|
+
/** Group chat: members */
|
|
93
|
+
GROUP_CHAT_MEMBERS: "group_chat_members",
|
|
94
|
+
/** Group chat: processed event IDs for deduplication */
|
|
95
|
+
GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events",
|
|
96
|
+
/** Group chat: last used relay URL (stale data detection) */
|
|
97
|
+
GROUP_CHAT_RELAY_URL: "group_chat_relay_url"
|
|
88
98
|
};
|
|
89
99
|
var STORAGE_KEYS_ADDRESS = {
|
|
90
100
|
/** Pending transfers for this address */
|
|
@@ -165,27 +175,33 @@ var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
|
165
175
|
var TEST_NOSTR_RELAYS = [
|
|
166
176
|
"wss://nostr-relay.testnet.unicity.network"
|
|
167
177
|
];
|
|
178
|
+
var DEFAULT_GROUP_RELAYS = [
|
|
179
|
+
"wss://sphere-relay.unicity.network"
|
|
180
|
+
];
|
|
168
181
|
var NETWORKS = {
|
|
169
182
|
mainnet: {
|
|
170
183
|
name: "Mainnet",
|
|
171
184
|
aggregatorUrl: DEFAULT_AGGREGATOR_URL,
|
|
172
185
|
nostrRelays: DEFAULT_NOSTR_RELAYS,
|
|
173
186
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
174
|
-
electrumUrl: DEFAULT_ELECTRUM_URL
|
|
187
|
+
electrumUrl: DEFAULT_ELECTRUM_URL,
|
|
188
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
175
189
|
},
|
|
176
190
|
testnet: {
|
|
177
191
|
name: "Testnet",
|
|
178
192
|
aggregatorUrl: TEST_AGGREGATOR_URL,
|
|
179
193
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
180
194
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
181
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
195
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
196
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
182
197
|
},
|
|
183
198
|
dev: {
|
|
184
199
|
name: "Development",
|
|
185
200
|
aggregatorUrl: DEV_AGGREGATOR_URL,
|
|
186
201
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
187
202
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
188
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
203
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
204
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
189
205
|
}
|
|
190
206
|
};
|
|
191
207
|
var TIMEOUTS = {
|
|
@@ -605,29 +621,6 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
605
621
|
}
|
|
606
622
|
}
|
|
607
623
|
// =========================================================================
|
|
608
|
-
// Helper methods for individual token operations
|
|
609
|
-
// =========================================================================
|
|
610
|
-
async deleteToken(tokenId) {
|
|
611
|
-
if (this.db) {
|
|
612
|
-
await this.deleteFromStore(STORE_TOKENS, tokenId);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
async saveToken(tokenId, tokenData) {
|
|
616
|
-
if (this.db) {
|
|
617
|
-
await this.putToStore(STORE_TOKENS, tokenId, { id: tokenId, data: tokenData });
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
async getToken(tokenId) {
|
|
621
|
-
if (!this.db) return null;
|
|
622
|
-
const result = await this.getFromStore(STORE_TOKENS, tokenId);
|
|
623
|
-
return result?.data ?? null;
|
|
624
|
-
}
|
|
625
|
-
async listTokenIds() {
|
|
626
|
-
if (!this.db) return [];
|
|
627
|
-
const tokens = await this.getAllFromStore(STORE_TOKENS);
|
|
628
|
-
return tokens.map((t) => t.id);
|
|
629
|
-
}
|
|
630
|
-
// =========================================================================
|
|
631
624
|
// Private IndexedDB helpers
|
|
632
625
|
// =========================================================================
|
|
633
626
|
openDatabase() {
|
|
@@ -3900,9 +3893,13 @@ function mergeTxfData(local, remote) {
|
|
|
3900
3893
|
remote._invalid ?? [],
|
|
3901
3894
|
"tokenId"
|
|
3902
3895
|
);
|
|
3896
|
+
const localNametags = local._nametags ?? [];
|
|
3897
|
+
const remoteNametags = remote._nametags ?? [];
|
|
3898
|
+
const mergedNametags = mergeNametagsByName(localNametags, remoteNametags);
|
|
3903
3899
|
const merged = {
|
|
3904
3900
|
_meta: mergedMeta,
|
|
3905
3901
|
_tombstones: mergedTombstones.length > 0 ? mergedTombstones : void 0,
|
|
3902
|
+
_nametags: mergedNametags.length > 0 ? mergedNametags : void 0,
|
|
3906
3903
|
_outbox: mergedOutbox.length > 0 ? mergedOutbox : void 0,
|
|
3907
3904
|
_sent: mergedSent.length > 0 ? mergedSent : void 0,
|
|
3908
3905
|
_invalid: mergedInvalid.length > 0 ? mergedInvalid : void 0,
|
|
@@ -3929,6 +3926,7 @@ function getTokenKeys(data) {
|
|
|
3929
3926
|
"_sent",
|
|
3930
3927
|
"_invalid",
|
|
3931
3928
|
"_nametag",
|
|
3929
|
+
"_nametags",
|
|
3932
3930
|
"_mintOutbox",
|
|
3933
3931
|
"_invalidatedNametags",
|
|
3934
3932
|
"_integrity"
|
|
@@ -3936,7 +3934,7 @@ function getTokenKeys(data) {
|
|
|
3936
3934
|
const keys = /* @__PURE__ */ new Set();
|
|
3937
3935
|
for (const key of Object.keys(data)) {
|
|
3938
3936
|
if (reservedKeys.has(key)) continue;
|
|
3939
|
-
if (key.startsWith("archived-") || key.startsWith("_forked_")
|
|
3937
|
+
if (key.startsWith("archived-") || key.startsWith("_forked_")) continue;
|
|
3940
3938
|
keys.add(key);
|
|
3941
3939
|
}
|
|
3942
3940
|
return keys;
|
|
@@ -3951,6 +3949,18 @@ function isTokenTombstoned(tokenId, localToken, remoteToken, tombstoneKeys) {
|
|
|
3951
3949
|
void remoteToken;
|
|
3952
3950
|
return false;
|
|
3953
3951
|
}
|
|
3952
|
+
function mergeNametagsByName(local, remote) {
|
|
3953
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3954
|
+
for (const item of local) {
|
|
3955
|
+
if (item.name) seen.set(item.name, item);
|
|
3956
|
+
}
|
|
3957
|
+
for (const item of remote) {
|
|
3958
|
+
if (item.name && !seen.has(item.name)) {
|
|
3959
|
+
seen.set(item.name, item);
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
return Array.from(seen.values());
|
|
3963
|
+
}
|
|
3954
3964
|
function mergeArrayById(local, remote, idField) {
|
|
3955
3965
|
const seen = /* @__PURE__ */ new Map();
|
|
3956
3966
|
for (const item of local) {
|
|
@@ -4305,14 +4315,11 @@ var AsyncSerialQueue = class {
|
|
|
4305
4315
|
var WriteBuffer = class {
|
|
4306
4316
|
/** Full TXF data from save() calls — latest wins */
|
|
4307
4317
|
txfData = null;
|
|
4308
|
-
/** Individual token mutations: key -> { op: 'save'|'delete', data? } */
|
|
4309
|
-
tokenMutations = /* @__PURE__ */ new Map();
|
|
4310
4318
|
get isEmpty() {
|
|
4311
|
-
return this.txfData === null
|
|
4319
|
+
return this.txfData === null;
|
|
4312
4320
|
}
|
|
4313
4321
|
clear() {
|
|
4314
4322
|
this.txfData = null;
|
|
4315
|
-
this.tokenMutations.clear();
|
|
4316
4323
|
}
|
|
4317
4324
|
/**
|
|
4318
4325
|
* Merge another buffer's contents into this one (for rollback).
|
|
@@ -4322,11 +4329,6 @@ var WriteBuffer = class {
|
|
|
4322
4329
|
if (other.txfData && !this.txfData) {
|
|
4323
4330
|
this.txfData = other.txfData;
|
|
4324
4331
|
}
|
|
4325
|
-
for (const [id, mutation] of other.tokenMutations) {
|
|
4326
|
-
if (!this.tokenMutations.has(id)) {
|
|
4327
|
-
this.tokenMutations.set(id, mutation);
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
4330
4332
|
}
|
|
4331
4333
|
};
|
|
4332
4334
|
|
|
@@ -4366,9 +4368,6 @@ var IpfsStorageProvider = class {
|
|
|
4366
4368
|
subscriptionClient = null;
|
|
4367
4369
|
/** Unsubscribe function from subscription client */
|
|
4368
4370
|
subscriptionUnsubscribe = null;
|
|
4369
|
-
/** In-memory buffer for individual token save/delete calls */
|
|
4370
|
-
tokenBuffer = /* @__PURE__ */ new Map();
|
|
4371
|
-
deletedTokenIds = /* @__PURE__ */ new Set();
|
|
4372
4371
|
/** Write-behind buffer: serializes flush / sync / shutdown */
|
|
4373
4372
|
flushQueue = new AsyncSerialQueue();
|
|
4374
4373
|
/** Pending mutations not yet flushed to IPFS */
|
|
@@ -4557,14 +4556,6 @@ var IpfsStorageProvider = class {
|
|
|
4557
4556
|
metaUpdate.lastCid = this.remoteCid;
|
|
4558
4557
|
}
|
|
4559
4558
|
const updatedData = { ...data, _meta: metaUpdate };
|
|
4560
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4561
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4562
|
-
updatedData[tokenId] = tokenData;
|
|
4563
|
-
}
|
|
4564
|
-
}
|
|
4565
|
-
for (const tokenId of this.deletedTokenIds) {
|
|
4566
|
-
delete updatedData[tokenId];
|
|
4567
|
-
}
|
|
4568
4559
|
const { cid } = await this.httpClient.upload(updatedData);
|
|
4569
4560
|
this.log(`Content uploaded: CID=${cid}`);
|
|
4570
4561
|
const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence ? this.ipnsSequenceNumber : this.lastKnownRemoteSequence;
|
|
@@ -4603,7 +4594,6 @@ var IpfsStorageProvider = class {
|
|
|
4603
4594
|
lastCid: cid,
|
|
4604
4595
|
version: this.dataVersion
|
|
4605
4596
|
});
|
|
4606
|
-
this.deletedTokenIds.clear();
|
|
4607
4597
|
this.emitEvent({
|
|
4608
4598
|
type: "storage:saved",
|
|
4609
4599
|
timestamp: Date.now(),
|
|
@@ -4715,7 +4705,6 @@ var IpfsStorageProvider = class {
|
|
|
4715
4705
|
if (typeof remoteVersion === "number" && remoteVersion > this.dataVersion) {
|
|
4716
4706
|
this.dataVersion = remoteVersion;
|
|
4717
4707
|
}
|
|
4718
|
-
this.populateTokenBuffer(data);
|
|
4719
4708
|
this.emitEvent({
|
|
4720
4709
|
type: "storage:loaded",
|
|
4721
4710
|
timestamp: Date.now(),
|
|
@@ -4761,7 +4750,7 @@ var IpfsStorageProvider = class {
|
|
|
4761
4750
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4762
4751
|
return {
|
|
4763
4752
|
success: saveResult2.success,
|
|
4764
|
-
merged:
|
|
4753
|
+
merged: localData,
|
|
4765
4754
|
added: 0,
|
|
4766
4755
|
removed: 0,
|
|
4767
4756
|
conflicts: 0,
|
|
@@ -4776,7 +4765,7 @@ var IpfsStorageProvider = class {
|
|
|
4776
4765
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4777
4766
|
return {
|
|
4778
4767
|
success: true,
|
|
4779
|
-
merged:
|
|
4768
|
+
merged: localData,
|
|
4780
4769
|
added: 0,
|
|
4781
4770
|
removed: 0,
|
|
4782
4771
|
conflicts: 0
|
|
@@ -4799,7 +4788,7 @@ var IpfsStorageProvider = class {
|
|
|
4799
4788
|
});
|
|
4800
4789
|
return {
|
|
4801
4790
|
success: saveResult.success,
|
|
4802
|
-
merged
|
|
4791
|
+
merged,
|
|
4803
4792
|
added,
|
|
4804
4793
|
removed,
|
|
4805
4794
|
conflicts,
|
|
@@ -4825,21 +4814,6 @@ var IpfsStorageProvider = class {
|
|
|
4825
4814
|
// ---------------------------------------------------------------------------
|
|
4826
4815
|
// Private Helpers
|
|
4827
4816
|
// ---------------------------------------------------------------------------
|
|
4828
|
-
/**
|
|
4829
|
-
* Enrich TXF data with individually-buffered tokens before returning to caller.
|
|
4830
|
-
* PaymentsModule.createStorageData() passes empty tokens (they're stored via
|
|
4831
|
-
* saveToken()), but loadFromStorageData() needs them in the merged result.
|
|
4832
|
-
*/
|
|
4833
|
-
enrichWithTokenBuffer(data) {
|
|
4834
|
-
if (this.tokenBuffer.size === 0) return data;
|
|
4835
|
-
const enriched = { ...data };
|
|
4836
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4837
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4838
|
-
enriched[tokenId] = tokenData;
|
|
4839
|
-
}
|
|
4840
|
-
}
|
|
4841
|
-
return enriched;
|
|
4842
|
-
}
|
|
4843
4817
|
// ---------------------------------------------------------------------------
|
|
4844
4818
|
// Optional Methods
|
|
4845
4819
|
// ---------------------------------------------------------------------------
|
|
@@ -4869,8 +4843,6 @@ var IpfsStorageProvider = class {
|
|
|
4869
4843
|
const result = await this._doSave(emptyData);
|
|
4870
4844
|
if (result.success) {
|
|
4871
4845
|
this.cache.clear();
|
|
4872
|
-
this.tokenBuffer.clear();
|
|
4873
|
-
this.deletedTokenIds.clear();
|
|
4874
4846
|
await this.statePersistence.clear(this.ipnsName);
|
|
4875
4847
|
}
|
|
4876
4848
|
return result.success;
|
|
@@ -4881,27 +4853,6 @@ var IpfsStorageProvider = class {
|
|
|
4881
4853
|
this.eventCallbacks.delete(callback);
|
|
4882
4854
|
};
|
|
4883
4855
|
}
|
|
4884
|
-
async saveToken(tokenId, tokenData) {
|
|
4885
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "save", data: tokenData });
|
|
4886
|
-
this.tokenBuffer.set(tokenId, tokenData);
|
|
4887
|
-
this.deletedTokenIds.delete(tokenId);
|
|
4888
|
-
this.scheduleFlush();
|
|
4889
|
-
}
|
|
4890
|
-
async getToken(tokenId) {
|
|
4891
|
-
if (this.deletedTokenIds.has(tokenId)) return null;
|
|
4892
|
-
return this.tokenBuffer.get(tokenId) ?? null;
|
|
4893
|
-
}
|
|
4894
|
-
async listTokenIds() {
|
|
4895
|
-
return Array.from(this.tokenBuffer.keys()).filter(
|
|
4896
|
-
(id) => !this.deletedTokenIds.has(id)
|
|
4897
|
-
);
|
|
4898
|
-
}
|
|
4899
|
-
async deleteToken(tokenId) {
|
|
4900
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "delete" });
|
|
4901
|
-
this.tokenBuffer.delete(tokenId);
|
|
4902
|
-
this.deletedTokenIds.add(tokenId);
|
|
4903
|
-
this.scheduleFlush();
|
|
4904
|
-
}
|
|
4905
4856
|
// ---------------------------------------------------------------------------
|
|
4906
4857
|
// Public Accessors
|
|
4907
4858
|
// ---------------------------------------------------------------------------
|
|
@@ -4993,26 +4944,6 @@ var IpfsStorageProvider = class {
|
|
|
4993
4944
|
console.log(`[IPFS-Storage] ${message}`);
|
|
4994
4945
|
}
|
|
4995
4946
|
}
|
|
4996
|
-
META_KEYS = /* @__PURE__ */ new Set([
|
|
4997
|
-
"_meta",
|
|
4998
|
-
"_tombstones",
|
|
4999
|
-
"_outbox",
|
|
5000
|
-
"_sent",
|
|
5001
|
-
"_invalid",
|
|
5002
|
-
"_nametag",
|
|
5003
|
-
"_mintOutbox",
|
|
5004
|
-
"_invalidatedNametags",
|
|
5005
|
-
"_integrity"
|
|
5006
|
-
]);
|
|
5007
|
-
populateTokenBuffer(data) {
|
|
5008
|
-
this.tokenBuffer.clear();
|
|
5009
|
-
this.deletedTokenIds.clear();
|
|
5010
|
-
for (const key of Object.keys(data)) {
|
|
5011
|
-
if (!this.META_KEYS.has(key)) {
|
|
5012
|
-
this.tokenBuffer.set(key, data[key]);
|
|
5013
|
-
}
|
|
5014
|
-
}
|
|
5015
|
-
}
|
|
5016
4947
|
};
|
|
5017
4948
|
|
|
5018
4949
|
// impl/browser/ipfs/browser-ipfs-state-persistence.ts
|
|
@@ -5251,6 +5182,20 @@ function resolveArrayConfig(defaults, replace, additional) {
|
|
|
5251
5182
|
}
|
|
5252
5183
|
return result;
|
|
5253
5184
|
}
|
|
5185
|
+
function resolveGroupChatConfig(network, config) {
|
|
5186
|
+
if (!config) return void 0;
|
|
5187
|
+
if (config === true) {
|
|
5188
|
+
const netConfig2 = getNetworkConfig(network);
|
|
5189
|
+
return { relays: [...netConfig2.groupRelays] };
|
|
5190
|
+
}
|
|
5191
|
+
if (typeof config === "object" && config.enabled === false) {
|
|
5192
|
+
return void 0;
|
|
5193
|
+
}
|
|
5194
|
+
const netConfig = getNetworkConfig(network);
|
|
5195
|
+
return {
|
|
5196
|
+
relays: config.relays ?? [...netConfig.groupRelays]
|
|
5197
|
+
};
|
|
5198
|
+
}
|
|
5254
5199
|
|
|
5255
5200
|
// impl/browser/index.ts
|
|
5256
5201
|
if (typeof globalThis.Buffer === "undefined") {
|
|
@@ -5316,8 +5261,10 @@ function createBrowserProviders(config) {
|
|
|
5316
5261
|
debug: config?.tokenSync?.ipfs?.useDht
|
|
5317
5262
|
// reuse debug-like flag
|
|
5318
5263
|
}) : void 0;
|
|
5264
|
+
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
5319
5265
|
return {
|
|
5320
5266
|
storage,
|
|
5267
|
+
groupChat,
|
|
5321
5268
|
transport: createNostrTransportProvider({
|
|
5322
5269
|
relays: transportConfig.relays,
|
|
5323
5270
|
timeout: transportConfig.timeout,
|