@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
|
@@ -76,7 +76,17 @@ var STORAGE_KEYS_GLOBAL = {
|
|
|
76
76
|
/** Active addresses registry (JSON: TrackedAddressesStorage) */
|
|
77
77
|
TRACKED_ADDRESSES: "tracked_addresses",
|
|
78
78
|
/** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
|
|
79
|
-
LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
|
|
79
|
+
LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
|
|
80
|
+
/** Group chat: joined groups */
|
|
81
|
+
GROUP_CHAT_GROUPS: "group_chat_groups",
|
|
82
|
+
/** Group chat: messages */
|
|
83
|
+
GROUP_CHAT_MESSAGES: "group_chat_messages",
|
|
84
|
+
/** Group chat: members */
|
|
85
|
+
GROUP_CHAT_MEMBERS: "group_chat_members",
|
|
86
|
+
/** Group chat: processed event IDs for deduplication */
|
|
87
|
+
GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events",
|
|
88
|
+
/** Group chat: last used relay URL (stale data detection) */
|
|
89
|
+
GROUP_CHAT_RELAY_URL: "group_chat_relay_url"
|
|
80
90
|
};
|
|
81
91
|
var STORAGE_KEYS_ADDRESS = {
|
|
82
92
|
/** Pending transfers for this address */
|
|
@@ -157,27 +167,33 @@ var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
|
157
167
|
var TEST_NOSTR_RELAYS = [
|
|
158
168
|
"wss://nostr-relay.testnet.unicity.network"
|
|
159
169
|
];
|
|
170
|
+
var DEFAULT_GROUP_RELAYS = [
|
|
171
|
+
"wss://sphere-relay.unicity.network"
|
|
172
|
+
];
|
|
160
173
|
var NETWORKS = {
|
|
161
174
|
mainnet: {
|
|
162
175
|
name: "Mainnet",
|
|
163
176
|
aggregatorUrl: DEFAULT_AGGREGATOR_URL,
|
|
164
177
|
nostrRelays: DEFAULT_NOSTR_RELAYS,
|
|
165
178
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
166
|
-
electrumUrl: DEFAULT_ELECTRUM_URL
|
|
179
|
+
electrumUrl: DEFAULT_ELECTRUM_URL,
|
|
180
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
167
181
|
},
|
|
168
182
|
testnet: {
|
|
169
183
|
name: "Testnet",
|
|
170
184
|
aggregatorUrl: TEST_AGGREGATOR_URL,
|
|
171
185
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
172
186
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
173
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
187
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
188
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
174
189
|
},
|
|
175
190
|
dev: {
|
|
176
191
|
name: "Development",
|
|
177
192
|
aggregatorUrl: DEV_AGGREGATOR_URL,
|
|
178
193
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
179
194
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
180
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
195
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
196
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
181
197
|
}
|
|
182
198
|
};
|
|
183
199
|
var TIMEOUTS = {
|
|
@@ -494,34 +510,6 @@ var FileTokenStorageProvider = class {
|
|
|
494
510
|
return false;
|
|
495
511
|
}
|
|
496
512
|
}
|
|
497
|
-
async deleteToken(tokenId) {
|
|
498
|
-
const filePath = path2.join(this.tokensDir, `${tokenId}.json`);
|
|
499
|
-
if (fs2.existsSync(filePath)) {
|
|
500
|
-
fs2.unlinkSync(filePath);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
async saveToken(tokenId, tokenData) {
|
|
504
|
-
fs2.writeFileSync(
|
|
505
|
-
path2.join(this.tokensDir, `${tokenId}.json`),
|
|
506
|
-
JSON.stringify(tokenData, null, 2)
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
async getToken(tokenId) {
|
|
510
|
-
const filePath = path2.join(this.tokensDir, `${tokenId}.json`);
|
|
511
|
-
if (!fs2.existsSync(filePath)) {
|
|
512
|
-
return null;
|
|
513
|
-
}
|
|
514
|
-
try {
|
|
515
|
-
const content = fs2.readFileSync(filePath, "utf-8");
|
|
516
|
-
return JSON.parse(content);
|
|
517
|
-
} catch {
|
|
518
|
-
return null;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
async listTokenIds() {
|
|
522
|
-
const files = fs2.readdirSync(this.tokensDir).filter((f) => f.endsWith(".json") && f !== "_meta.json");
|
|
523
|
-
return files.map((f) => path2.basename(f, ".json"));
|
|
524
|
-
}
|
|
525
513
|
};
|
|
526
514
|
function createFileTokenStorageProvider(config) {
|
|
527
515
|
return new FileTokenStorageProvider(config);
|
|
@@ -3657,9 +3645,13 @@ function mergeTxfData(local, remote) {
|
|
|
3657
3645
|
remote._invalid ?? [],
|
|
3658
3646
|
"tokenId"
|
|
3659
3647
|
);
|
|
3648
|
+
const localNametags = local._nametags ?? [];
|
|
3649
|
+
const remoteNametags = remote._nametags ?? [];
|
|
3650
|
+
const mergedNametags = mergeNametagsByName(localNametags, remoteNametags);
|
|
3660
3651
|
const merged = {
|
|
3661
3652
|
_meta: mergedMeta,
|
|
3662
3653
|
_tombstones: mergedTombstones.length > 0 ? mergedTombstones : void 0,
|
|
3654
|
+
_nametags: mergedNametags.length > 0 ? mergedNametags : void 0,
|
|
3663
3655
|
_outbox: mergedOutbox.length > 0 ? mergedOutbox : void 0,
|
|
3664
3656
|
_sent: mergedSent.length > 0 ? mergedSent : void 0,
|
|
3665
3657
|
_invalid: mergedInvalid.length > 0 ? mergedInvalid : void 0,
|
|
@@ -3686,6 +3678,7 @@ function getTokenKeys(data) {
|
|
|
3686
3678
|
"_sent",
|
|
3687
3679
|
"_invalid",
|
|
3688
3680
|
"_nametag",
|
|
3681
|
+
"_nametags",
|
|
3689
3682
|
"_mintOutbox",
|
|
3690
3683
|
"_invalidatedNametags",
|
|
3691
3684
|
"_integrity"
|
|
@@ -3693,7 +3686,7 @@ function getTokenKeys(data) {
|
|
|
3693
3686
|
const keys = /* @__PURE__ */ new Set();
|
|
3694
3687
|
for (const key of Object.keys(data)) {
|
|
3695
3688
|
if (reservedKeys.has(key)) continue;
|
|
3696
|
-
if (key.startsWith("archived-") || key.startsWith("_forked_")
|
|
3689
|
+
if (key.startsWith("archived-") || key.startsWith("_forked_")) continue;
|
|
3697
3690
|
keys.add(key);
|
|
3698
3691
|
}
|
|
3699
3692
|
return keys;
|
|
@@ -3708,6 +3701,18 @@ function isTokenTombstoned(tokenId, localToken, remoteToken, tombstoneKeys) {
|
|
|
3708
3701
|
void remoteToken;
|
|
3709
3702
|
return false;
|
|
3710
3703
|
}
|
|
3704
|
+
function mergeNametagsByName(local, remote) {
|
|
3705
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3706
|
+
for (const item of local) {
|
|
3707
|
+
if (item.name) seen.set(item.name, item);
|
|
3708
|
+
}
|
|
3709
|
+
for (const item of remote) {
|
|
3710
|
+
if (item.name && !seen.has(item.name)) {
|
|
3711
|
+
seen.set(item.name, item);
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
return Array.from(seen.values());
|
|
3715
|
+
}
|
|
3711
3716
|
function mergeArrayById(local, remote, idField) {
|
|
3712
3717
|
const seen = /* @__PURE__ */ new Map();
|
|
3713
3718
|
for (const item of local) {
|
|
@@ -4062,14 +4067,11 @@ var AsyncSerialQueue = class {
|
|
|
4062
4067
|
var WriteBuffer = class {
|
|
4063
4068
|
/** Full TXF data from save() calls — latest wins */
|
|
4064
4069
|
txfData = null;
|
|
4065
|
-
/** Individual token mutations: key -> { op: 'save'|'delete', data? } */
|
|
4066
|
-
tokenMutations = /* @__PURE__ */ new Map();
|
|
4067
4070
|
get isEmpty() {
|
|
4068
|
-
return this.txfData === null
|
|
4071
|
+
return this.txfData === null;
|
|
4069
4072
|
}
|
|
4070
4073
|
clear() {
|
|
4071
4074
|
this.txfData = null;
|
|
4072
|
-
this.tokenMutations.clear();
|
|
4073
4075
|
}
|
|
4074
4076
|
/**
|
|
4075
4077
|
* Merge another buffer's contents into this one (for rollback).
|
|
@@ -4079,11 +4081,6 @@ var WriteBuffer = class {
|
|
|
4079
4081
|
if (other.txfData && !this.txfData) {
|
|
4080
4082
|
this.txfData = other.txfData;
|
|
4081
4083
|
}
|
|
4082
|
-
for (const [id, mutation] of other.tokenMutations) {
|
|
4083
|
-
if (!this.tokenMutations.has(id)) {
|
|
4084
|
-
this.tokenMutations.set(id, mutation);
|
|
4085
|
-
}
|
|
4086
|
-
}
|
|
4087
4084
|
}
|
|
4088
4085
|
};
|
|
4089
4086
|
|
|
@@ -4123,9 +4120,6 @@ var IpfsStorageProvider = class {
|
|
|
4123
4120
|
subscriptionClient = null;
|
|
4124
4121
|
/** Unsubscribe function from subscription client */
|
|
4125
4122
|
subscriptionUnsubscribe = null;
|
|
4126
|
-
/** In-memory buffer for individual token save/delete calls */
|
|
4127
|
-
tokenBuffer = /* @__PURE__ */ new Map();
|
|
4128
|
-
deletedTokenIds = /* @__PURE__ */ new Set();
|
|
4129
4123
|
/** Write-behind buffer: serializes flush / sync / shutdown */
|
|
4130
4124
|
flushQueue = new AsyncSerialQueue();
|
|
4131
4125
|
/** Pending mutations not yet flushed to IPFS */
|
|
@@ -4314,14 +4308,6 @@ var IpfsStorageProvider = class {
|
|
|
4314
4308
|
metaUpdate.lastCid = this.remoteCid;
|
|
4315
4309
|
}
|
|
4316
4310
|
const updatedData = { ...data, _meta: metaUpdate };
|
|
4317
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4318
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4319
|
-
updatedData[tokenId] = tokenData;
|
|
4320
|
-
}
|
|
4321
|
-
}
|
|
4322
|
-
for (const tokenId of this.deletedTokenIds) {
|
|
4323
|
-
delete updatedData[tokenId];
|
|
4324
|
-
}
|
|
4325
4311
|
const { cid } = await this.httpClient.upload(updatedData);
|
|
4326
4312
|
this.log(`Content uploaded: CID=${cid}`);
|
|
4327
4313
|
const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence ? this.ipnsSequenceNumber : this.lastKnownRemoteSequence;
|
|
@@ -4360,7 +4346,6 @@ var IpfsStorageProvider = class {
|
|
|
4360
4346
|
lastCid: cid,
|
|
4361
4347
|
version: this.dataVersion
|
|
4362
4348
|
});
|
|
4363
|
-
this.deletedTokenIds.clear();
|
|
4364
4349
|
this.emitEvent({
|
|
4365
4350
|
type: "storage:saved",
|
|
4366
4351
|
timestamp: Date.now(),
|
|
@@ -4472,7 +4457,6 @@ var IpfsStorageProvider = class {
|
|
|
4472
4457
|
if (typeof remoteVersion === "number" && remoteVersion > this.dataVersion) {
|
|
4473
4458
|
this.dataVersion = remoteVersion;
|
|
4474
4459
|
}
|
|
4475
|
-
this.populateTokenBuffer(data);
|
|
4476
4460
|
this.emitEvent({
|
|
4477
4461
|
type: "storage:loaded",
|
|
4478
4462
|
timestamp: Date.now(),
|
|
@@ -4518,7 +4502,7 @@ var IpfsStorageProvider = class {
|
|
|
4518
4502
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4519
4503
|
return {
|
|
4520
4504
|
success: saveResult2.success,
|
|
4521
|
-
merged:
|
|
4505
|
+
merged: localData,
|
|
4522
4506
|
added: 0,
|
|
4523
4507
|
removed: 0,
|
|
4524
4508
|
conflicts: 0,
|
|
@@ -4533,7 +4517,7 @@ var IpfsStorageProvider = class {
|
|
|
4533
4517
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4534
4518
|
return {
|
|
4535
4519
|
success: true,
|
|
4536
|
-
merged:
|
|
4520
|
+
merged: localData,
|
|
4537
4521
|
added: 0,
|
|
4538
4522
|
removed: 0,
|
|
4539
4523
|
conflicts: 0
|
|
@@ -4556,7 +4540,7 @@ var IpfsStorageProvider = class {
|
|
|
4556
4540
|
});
|
|
4557
4541
|
return {
|
|
4558
4542
|
success: saveResult.success,
|
|
4559
|
-
merged
|
|
4543
|
+
merged,
|
|
4560
4544
|
added,
|
|
4561
4545
|
removed,
|
|
4562
4546
|
conflicts,
|
|
@@ -4582,21 +4566,6 @@ var IpfsStorageProvider = class {
|
|
|
4582
4566
|
// ---------------------------------------------------------------------------
|
|
4583
4567
|
// Private Helpers
|
|
4584
4568
|
// ---------------------------------------------------------------------------
|
|
4585
|
-
/**
|
|
4586
|
-
* Enrich TXF data with individually-buffered tokens before returning to caller.
|
|
4587
|
-
* PaymentsModule.createStorageData() passes empty tokens (they're stored via
|
|
4588
|
-
* saveToken()), but loadFromStorageData() needs them in the merged result.
|
|
4589
|
-
*/
|
|
4590
|
-
enrichWithTokenBuffer(data) {
|
|
4591
|
-
if (this.tokenBuffer.size === 0) return data;
|
|
4592
|
-
const enriched = { ...data };
|
|
4593
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4594
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4595
|
-
enriched[tokenId] = tokenData;
|
|
4596
|
-
}
|
|
4597
|
-
}
|
|
4598
|
-
return enriched;
|
|
4599
|
-
}
|
|
4600
4569
|
// ---------------------------------------------------------------------------
|
|
4601
4570
|
// Optional Methods
|
|
4602
4571
|
// ---------------------------------------------------------------------------
|
|
@@ -4626,8 +4595,6 @@ var IpfsStorageProvider = class {
|
|
|
4626
4595
|
const result = await this._doSave(emptyData);
|
|
4627
4596
|
if (result.success) {
|
|
4628
4597
|
this.cache.clear();
|
|
4629
|
-
this.tokenBuffer.clear();
|
|
4630
|
-
this.deletedTokenIds.clear();
|
|
4631
4598
|
await this.statePersistence.clear(this.ipnsName);
|
|
4632
4599
|
}
|
|
4633
4600
|
return result.success;
|
|
@@ -4638,27 +4605,6 @@ var IpfsStorageProvider = class {
|
|
|
4638
4605
|
this.eventCallbacks.delete(callback);
|
|
4639
4606
|
};
|
|
4640
4607
|
}
|
|
4641
|
-
async saveToken(tokenId, tokenData) {
|
|
4642
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "save", data: tokenData });
|
|
4643
|
-
this.tokenBuffer.set(tokenId, tokenData);
|
|
4644
|
-
this.deletedTokenIds.delete(tokenId);
|
|
4645
|
-
this.scheduleFlush();
|
|
4646
|
-
}
|
|
4647
|
-
async getToken(tokenId) {
|
|
4648
|
-
if (this.deletedTokenIds.has(tokenId)) return null;
|
|
4649
|
-
return this.tokenBuffer.get(tokenId) ?? null;
|
|
4650
|
-
}
|
|
4651
|
-
async listTokenIds() {
|
|
4652
|
-
return Array.from(this.tokenBuffer.keys()).filter(
|
|
4653
|
-
(id) => !this.deletedTokenIds.has(id)
|
|
4654
|
-
);
|
|
4655
|
-
}
|
|
4656
|
-
async deleteToken(tokenId) {
|
|
4657
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "delete" });
|
|
4658
|
-
this.tokenBuffer.delete(tokenId);
|
|
4659
|
-
this.deletedTokenIds.add(tokenId);
|
|
4660
|
-
this.scheduleFlush();
|
|
4661
|
-
}
|
|
4662
4608
|
// ---------------------------------------------------------------------------
|
|
4663
4609
|
// Public Accessors
|
|
4664
4610
|
// ---------------------------------------------------------------------------
|
|
@@ -4750,26 +4696,6 @@ var IpfsStorageProvider = class {
|
|
|
4750
4696
|
console.log(`[IPFS-Storage] ${message}`);
|
|
4751
4697
|
}
|
|
4752
4698
|
}
|
|
4753
|
-
META_KEYS = /* @__PURE__ */ new Set([
|
|
4754
|
-
"_meta",
|
|
4755
|
-
"_tombstones",
|
|
4756
|
-
"_outbox",
|
|
4757
|
-
"_sent",
|
|
4758
|
-
"_invalid",
|
|
4759
|
-
"_nametag",
|
|
4760
|
-
"_mintOutbox",
|
|
4761
|
-
"_invalidatedNametags",
|
|
4762
|
-
"_integrity"
|
|
4763
|
-
]);
|
|
4764
|
-
populateTokenBuffer(data) {
|
|
4765
|
-
this.tokenBuffer.clear();
|
|
4766
|
-
this.deletedTokenIds.clear();
|
|
4767
|
-
for (const key of Object.keys(data)) {
|
|
4768
|
-
if (!this.META_KEYS.has(key)) {
|
|
4769
|
-
this.tokenBuffer.set(key, data[key]);
|
|
4770
|
-
}
|
|
4771
|
-
}
|
|
4772
|
-
}
|
|
4773
4699
|
};
|
|
4774
4700
|
|
|
4775
4701
|
// impl/nodejs/ipfs/nodejs-ipfs-state-persistence.ts
|
|
@@ -4995,6 +4921,20 @@ function resolvePriceConfig(config) {
|
|
|
4995
4921
|
debug: config.debug
|
|
4996
4922
|
};
|
|
4997
4923
|
}
|
|
4924
|
+
function resolveGroupChatConfig(network, config) {
|
|
4925
|
+
if (!config) return void 0;
|
|
4926
|
+
if (config === true) {
|
|
4927
|
+
const netConfig2 = getNetworkConfig(network);
|
|
4928
|
+
return { relays: [...netConfig2.groupRelays] };
|
|
4929
|
+
}
|
|
4930
|
+
if (typeof config === "object" && config.enabled === false) {
|
|
4931
|
+
return void 0;
|
|
4932
|
+
}
|
|
4933
|
+
const netConfig = getNetworkConfig(network);
|
|
4934
|
+
return {
|
|
4935
|
+
relays: config.relays ?? [...netConfig.groupRelays]
|
|
4936
|
+
};
|
|
4937
|
+
}
|
|
4998
4938
|
|
|
4999
4939
|
// impl/nodejs/index.ts
|
|
5000
4940
|
function createNodeProviders(config) {
|
|
@@ -5008,8 +4948,10 @@ function createNodeProviders(config) {
|
|
|
5008
4948
|
});
|
|
5009
4949
|
const ipfsSync = config?.tokenSync?.ipfs;
|
|
5010
4950
|
const ipfsTokenStorage = ipfsSync?.enabled ? createNodeIpfsStorageProvider(ipfsSync.config, storage) : void 0;
|
|
4951
|
+
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
5011
4952
|
return {
|
|
5012
4953
|
storage,
|
|
4954
|
+
groupChat,
|
|
5013
4955
|
tokenStorage: createFileTokenStorageProvider({
|
|
5014
4956
|
tokensDir: config?.tokensDir ?? "./sphere-tokens"
|
|
5015
4957
|
}),
|