@unicitylabs/sphere-sdk 0.2.5 → 0.3.0
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 +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
|
@@ -3,6 +3,19 @@ import { AggregatorClient } from '@unicitylabs/state-transition-sdk/lib/api/Aggr
|
|
|
3
3
|
import { RootTrustBase } from '@unicitylabs/state-transition-sdk/lib/bft/RootTrustBase';
|
|
4
4
|
import { TransferCommitment as TransferCommitment$1 } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';
|
|
5
5
|
|
|
6
|
+
interface GroupChatModuleConfig {
|
|
7
|
+
/** Override relay URLs (default: from network config) */
|
|
8
|
+
relays?: string[];
|
|
9
|
+
/** Default message fetch limit (default: 50) */
|
|
10
|
+
defaultMessageLimit?: number;
|
|
11
|
+
/** Max previous message IDs in ordering tags (default: 3) */
|
|
12
|
+
maxPreviousTags?: number;
|
|
13
|
+
/** Reconnect delay in ms (default: 3000) */
|
|
14
|
+
reconnectDelayMs?: number;
|
|
15
|
+
/** Max reconnect attempts (default: 5) */
|
|
16
|
+
maxReconnectAttempts?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
/**
|
|
7
20
|
* SDK2 Core Types
|
|
8
21
|
* Platform-independent type definitions
|
|
@@ -160,22 +173,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
|
|
|
160
173
|
* Subscribe to storage events
|
|
161
174
|
*/
|
|
162
175
|
onEvent?(callback: StorageEventCallback): () => void;
|
|
163
|
-
/**
|
|
164
|
-
* Save individual token (for file-based storage like lottery pattern)
|
|
165
|
-
*/
|
|
166
|
-
saveToken?(tokenId: string, tokenData: unknown): Promise<void>;
|
|
167
|
-
/**
|
|
168
|
-
* Get individual token
|
|
169
|
-
*/
|
|
170
|
-
getToken?(tokenId: string): Promise<unknown | null>;
|
|
171
|
-
/**
|
|
172
|
-
* List all token IDs
|
|
173
|
-
*/
|
|
174
|
-
listTokenIds?(): Promise<string[]>;
|
|
175
|
-
/**
|
|
176
|
-
* Delete individual token
|
|
177
|
-
*/
|
|
178
|
-
deleteToken?(tokenId: string): Promise<void>;
|
|
179
176
|
}
|
|
180
177
|
type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
|
|
181
178
|
interface StorageEvent {
|
|
@@ -301,10 +298,6 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
|
|
|
301
298
|
save(data: TxfStorageDataBase): Promise<SaveResult>;
|
|
302
299
|
sync(localData: TxfStorageDataBase): Promise<SyncResult<TxfStorageDataBase>>;
|
|
303
300
|
clear(): Promise<boolean>;
|
|
304
|
-
deleteToken(tokenId: string): Promise<void>;
|
|
305
|
-
saveToken(tokenId: string, tokenData: unknown): Promise<void>;
|
|
306
|
-
getToken(tokenId: string): Promise<unknown | null>;
|
|
307
|
-
listTokenIds(): Promise<string[]>;
|
|
308
301
|
}
|
|
309
302
|
declare function createFileTokenStorageProvider(config: FileTokenStorageConfig | string): FileTokenStorageProvider;
|
|
310
303
|
|
|
@@ -1117,6 +1110,7 @@ declare const NETWORKS: {
|
|
|
1117
1110
|
readonly nostrRelays: readonly ["wss://relay.unicity.network", "wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"];
|
|
1118
1111
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1119
1112
|
readonly electrumUrl: "wss://fulcrum.alpha.unicity.network:50004";
|
|
1113
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1120
1114
|
};
|
|
1121
1115
|
readonly testnet: {
|
|
1122
1116
|
readonly name: "Testnet";
|
|
@@ -1124,6 +1118,7 @@ declare const NETWORKS: {
|
|
|
1124
1118
|
readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
|
|
1125
1119
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1126
1120
|
readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
1121
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1127
1122
|
};
|
|
1128
1123
|
readonly dev: {
|
|
1129
1124
|
readonly name: "Development";
|
|
@@ -1131,6 +1126,7 @@ declare const NETWORKS: {
|
|
|
1131
1126
|
readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
|
|
1132
1127
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1133
1128
|
readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
1129
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1134
1130
|
};
|
|
1135
1131
|
};
|
|
1136
1132
|
type NetworkType = keyof typeof NETWORKS;
|
|
@@ -1415,6 +1411,11 @@ interface NodeProvidersConfig {
|
|
|
1415
1411
|
price?: BasePriceConfig;
|
|
1416
1412
|
/** Token sync backends configuration */
|
|
1417
1413
|
tokenSync?: NodeTokenSyncConfig;
|
|
1414
|
+
/** Group chat (NIP-29) configuration. true = enable with defaults, object = custom config */
|
|
1415
|
+
groupChat?: {
|
|
1416
|
+
enabled?: boolean;
|
|
1417
|
+
relays?: string[];
|
|
1418
|
+
} | boolean;
|
|
1418
1419
|
}
|
|
1419
1420
|
interface NodeProviders {
|
|
1420
1421
|
storage: StorageProvider;
|
|
@@ -1427,6 +1428,8 @@ interface NodeProviders {
|
|
|
1427
1428
|
price?: PriceProvider;
|
|
1428
1429
|
/** IPFS token storage provider (when tokenSync.ipfs.enabled is true) */
|
|
1429
1430
|
ipfsTokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
|
|
1431
|
+
/** Group chat config (resolved, for passing to Sphere.init) */
|
|
1432
|
+
groupChat?: GroupChatModuleConfig | boolean;
|
|
1430
1433
|
}
|
|
1431
1434
|
/**
|
|
1432
1435
|
* Create all Node.js providers with default configuration
|
|
@@ -3,6 +3,19 @@ import { AggregatorClient } from '@unicitylabs/state-transition-sdk/lib/api/Aggr
|
|
|
3
3
|
import { RootTrustBase } from '@unicitylabs/state-transition-sdk/lib/bft/RootTrustBase';
|
|
4
4
|
import { TransferCommitment as TransferCommitment$1 } from '@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment';
|
|
5
5
|
|
|
6
|
+
interface GroupChatModuleConfig {
|
|
7
|
+
/** Override relay URLs (default: from network config) */
|
|
8
|
+
relays?: string[];
|
|
9
|
+
/** Default message fetch limit (default: 50) */
|
|
10
|
+
defaultMessageLimit?: number;
|
|
11
|
+
/** Max previous message IDs in ordering tags (default: 3) */
|
|
12
|
+
maxPreviousTags?: number;
|
|
13
|
+
/** Reconnect delay in ms (default: 3000) */
|
|
14
|
+
reconnectDelayMs?: number;
|
|
15
|
+
/** Max reconnect attempts (default: 5) */
|
|
16
|
+
maxReconnectAttempts?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
/**
|
|
7
20
|
* SDK2 Core Types
|
|
8
21
|
* Platform-independent type definitions
|
|
@@ -160,22 +173,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
|
|
|
160
173
|
* Subscribe to storage events
|
|
161
174
|
*/
|
|
162
175
|
onEvent?(callback: StorageEventCallback): () => void;
|
|
163
|
-
/**
|
|
164
|
-
* Save individual token (for file-based storage like lottery pattern)
|
|
165
|
-
*/
|
|
166
|
-
saveToken?(tokenId: string, tokenData: unknown): Promise<void>;
|
|
167
|
-
/**
|
|
168
|
-
* Get individual token
|
|
169
|
-
*/
|
|
170
|
-
getToken?(tokenId: string): Promise<unknown | null>;
|
|
171
|
-
/**
|
|
172
|
-
* List all token IDs
|
|
173
|
-
*/
|
|
174
|
-
listTokenIds?(): Promise<string[]>;
|
|
175
|
-
/**
|
|
176
|
-
* Delete individual token
|
|
177
|
-
*/
|
|
178
|
-
deleteToken?(tokenId: string): Promise<void>;
|
|
179
176
|
}
|
|
180
177
|
type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
|
|
181
178
|
interface StorageEvent {
|
|
@@ -301,10 +298,6 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
|
|
|
301
298
|
save(data: TxfStorageDataBase): Promise<SaveResult>;
|
|
302
299
|
sync(localData: TxfStorageDataBase): Promise<SyncResult<TxfStorageDataBase>>;
|
|
303
300
|
clear(): Promise<boolean>;
|
|
304
|
-
deleteToken(tokenId: string): Promise<void>;
|
|
305
|
-
saveToken(tokenId: string, tokenData: unknown): Promise<void>;
|
|
306
|
-
getToken(tokenId: string): Promise<unknown | null>;
|
|
307
|
-
listTokenIds(): Promise<string[]>;
|
|
308
301
|
}
|
|
309
302
|
declare function createFileTokenStorageProvider(config: FileTokenStorageConfig | string): FileTokenStorageProvider;
|
|
310
303
|
|
|
@@ -1117,6 +1110,7 @@ declare const NETWORKS: {
|
|
|
1117
1110
|
readonly nostrRelays: readonly ["wss://relay.unicity.network", "wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"];
|
|
1118
1111
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1119
1112
|
readonly electrumUrl: "wss://fulcrum.alpha.unicity.network:50004";
|
|
1113
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1120
1114
|
};
|
|
1121
1115
|
readonly testnet: {
|
|
1122
1116
|
readonly name: "Testnet";
|
|
@@ -1124,6 +1118,7 @@ declare const NETWORKS: {
|
|
|
1124
1118
|
readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
|
|
1125
1119
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1126
1120
|
readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
1121
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1127
1122
|
};
|
|
1128
1123
|
readonly dev: {
|
|
1129
1124
|
readonly name: "Development";
|
|
@@ -1131,6 +1126,7 @@ declare const NETWORKS: {
|
|
|
1131
1126
|
readonly nostrRelays: readonly ["wss://nostr-relay.testnet.unicity.network"];
|
|
1132
1127
|
readonly ipfsGateways: readonly ["https://ipfs.unicity.network", "https://dweb.link", "https://ipfs.io"];
|
|
1133
1128
|
readonly electrumUrl: "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
1129
|
+
readonly groupRelays: readonly ["wss://sphere-relay.unicity.network"];
|
|
1134
1130
|
};
|
|
1135
1131
|
};
|
|
1136
1132
|
type NetworkType = keyof typeof NETWORKS;
|
|
@@ -1415,6 +1411,11 @@ interface NodeProvidersConfig {
|
|
|
1415
1411
|
price?: BasePriceConfig;
|
|
1416
1412
|
/** Token sync backends configuration */
|
|
1417
1413
|
tokenSync?: NodeTokenSyncConfig;
|
|
1414
|
+
/** Group chat (NIP-29) configuration. true = enable with defaults, object = custom config */
|
|
1415
|
+
groupChat?: {
|
|
1416
|
+
enabled?: boolean;
|
|
1417
|
+
relays?: string[];
|
|
1418
|
+
} | boolean;
|
|
1418
1419
|
}
|
|
1419
1420
|
interface NodeProviders {
|
|
1420
1421
|
storage: StorageProvider;
|
|
@@ -1427,6 +1428,8 @@ interface NodeProviders {
|
|
|
1427
1428
|
price?: PriceProvider;
|
|
1428
1429
|
/** IPFS token storage provider (when tokenSync.ipfs.enabled is true) */
|
|
1429
1430
|
ipfsTokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
|
|
1431
|
+
/** Group chat config (resolved, for passing to Sphere.init) */
|
|
1432
|
+
groupChat?: GroupChatModuleConfig | boolean;
|
|
1430
1433
|
}
|
|
1431
1434
|
/**
|
|
1432
1435
|
* Create all Node.js providers with default configuration
|
|
@@ -27,7 +27,17 @@ var STORAGE_KEYS_GLOBAL = {
|
|
|
27
27
|
/** Active addresses registry (JSON: TrackedAddressesStorage) */
|
|
28
28
|
TRACKED_ADDRESSES: "tracked_addresses",
|
|
29
29
|
/** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
|
|
30
|
-
LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
|
|
30
|
+
LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
|
|
31
|
+
/** Group chat: joined groups */
|
|
32
|
+
GROUP_CHAT_GROUPS: "group_chat_groups",
|
|
33
|
+
/** Group chat: messages */
|
|
34
|
+
GROUP_CHAT_MESSAGES: "group_chat_messages",
|
|
35
|
+
/** Group chat: members */
|
|
36
|
+
GROUP_CHAT_MEMBERS: "group_chat_members",
|
|
37
|
+
/** Group chat: processed event IDs for deduplication */
|
|
38
|
+
GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events",
|
|
39
|
+
/** Group chat: last used relay URL (stale data detection) */
|
|
40
|
+
GROUP_CHAT_RELAY_URL: "group_chat_relay_url"
|
|
31
41
|
};
|
|
32
42
|
var STORAGE_KEYS_ADDRESS = {
|
|
33
43
|
/** Pending transfers for this address */
|
|
@@ -108,27 +118,33 @@ var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
|
108
118
|
var TEST_NOSTR_RELAYS = [
|
|
109
119
|
"wss://nostr-relay.testnet.unicity.network"
|
|
110
120
|
];
|
|
121
|
+
var DEFAULT_GROUP_RELAYS = [
|
|
122
|
+
"wss://sphere-relay.unicity.network"
|
|
123
|
+
];
|
|
111
124
|
var NETWORKS = {
|
|
112
125
|
mainnet: {
|
|
113
126
|
name: "Mainnet",
|
|
114
127
|
aggregatorUrl: DEFAULT_AGGREGATOR_URL,
|
|
115
128
|
nostrRelays: DEFAULT_NOSTR_RELAYS,
|
|
116
129
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
117
|
-
electrumUrl: DEFAULT_ELECTRUM_URL
|
|
130
|
+
electrumUrl: DEFAULT_ELECTRUM_URL,
|
|
131
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
118
132
|
},
|
|
119
133
|
testnet: {
|
|
120
134
|
name: "Testnet",
|
|
121
135
|
aggregatorUrl: TEST_AGGREGATOR_URL,
|
|
122
136
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
123
137
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
124
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
138
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
139
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
125
140
|
},
|
|
126
141
|
dev: {
|
|
127
142
|
name: "Development",
|
|
128
143
|
aggregatorUrl: DEV_AGGREGATOR_URL,
|
|
129
144
|
nostrRelays: TEST_NOSTR_RELAYS,
|
|
130
145
|
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
131
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
146
|
+
electrumUrl: TEST_ELECTRUM_URL,
|
|
147
|
+
groupRelays: DEFAULT_GROUP_RELAYS
|
|
132
148
|
}
|
|
133
149
|
};
|
|
134
150
|
var TIMEOUTS = {
|
|
@@ -445,34 +461,6 @@ var FileTokenStorageProvider = class {
|
|
|
445
461
|
return false;
|
|
446
462
|
}
|
|
447
463
|
}
|
|
448
|
-
async deleteToken(tokenId) {
|
|
449
|
-
const filePath = path2.join(this.tokensDir, `${tokenId}.json`);
|
|
450
|
-
if (fs2.existsSync(filePath)) {
|
|
451
|
-
fs2.unlinkSync(filePath);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
async saveToken(tokenId, tokenData) {
|
|
455
|
-
fs2.writeFileSync(
|
|
456
|
-
path2.join(this.tokensDir, `${tokenId}.json`),
|
|
457
|
-
JSON.stringify(tokenData, null, 2)
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
async getToken(tokenId) {
|
|
461
|
-
const filePath = path2.join(this.tokensDir, `${tokenId}.json`);
|
|
462
|
-
if (!fs2.existsSync(filePath)) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
try {
|
|
466
|
-
const content = fs2.readFileSync(filePath, "utf-8");
|
|
467
|
-
return JSON.parse(content);
|
|
468
|
-
} catch {
|
|
469
|
-
return null;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
async listTokenIds() {
|
|
473
|
-
const files = fs2.readdirSync(this.tokensDir).filter((f) => f.endsWith(".json") && f !== "_meta.json");
|
|
474
|
-
return files.map((f) => path2.basename(f, ".json"));
|
|
475
|
-
}
|
|
476
464
|
};
|
|
477
465
|
function createFileTokenStorageProvider(config) {
|
|
478
466
|
return new FileTokenStorageProvider(config);
|
|
@@ -3617,9 +3605,13 @@ function mergeTxfData(local, remote) {
|
|
|
3617
3605
|
remote._invalid ?? [],
|
|
3618
3606
|
"tokenId"
|
|
3619
3607
|
);
|
|
3608
|
+
const localNametags = local._nametags ?? [];
|
|
3609
|
+
const remoteNametags = remote._nametags ?? [];
|
|
3610
|
+
const mergedNametags = mergeNametagsByName(localNametags, remoteNametags);
|
|
3620
3611
|
const merged = {
|
|
3621
3612
|
_meta: mergedMeta,
|
|
3622
3613
|
_tombstones: mergedTombstones.length > 0 ? mergedTombstones : void 0,
|
|
3614
|
+
_nametags: mergedNametags.length > 0 ? mergedNametags : void 0,
|
|
3623
3615
|
_outbox: mergedOutbox.length > 0 ? mergedOutbox : void 0,
|
|
3624
3616
|
_sent: mergedSent.length > 0 ? mergedSent : void 0,
|
|
3625
3617
|
_invalid: mergedInvalid.length > 0 ? mergedInvalid : void 0,
|
|
@@ -3646,6 +3638,7 @@ function getTokenKeys(data) {
|
|
|
3646
3638
|
"_sent",
|
|
3647
3639
|
"_invalid",
|
|
3648
3640
|
"_nametag",
|
|
3641
|
+
"_nametags",
|
|
3649
3642
|
"_mintOutbox",
|
|
3650
3643
|
"_invalidatedNametags",
|
|
3651
3644
|
"_integrity"
|
|
@@ -3653,7 +3646,7 @@ function getTokenKeys(data) {
|
|
|
3653
3646
|
const keys = /* @__PURE__ */ new Set();
|
|
3654
3647
|
for (const key of Object.keys(data)) {
|
|
3655
3648
|
if (reservedKeys.has(key)) continue;
|
|
3656
|
-
if (key.startsWith("archived-") || key.startsWith("_forked_")
|
|
3649
|
+
if (key.startsWith("archived-") || key.startsWith("_forked_")) continue;
|
|
3657
3650
|
keys.add(key);
|
|
3658
3651
|
}
|
|
3659
3652
|
return keys;
|
|
@@ -3668,6 +3661,18 @@ function isTokenTombstoned(tokenId, localToken, remoteToken, tombstoneKeys) {
|
|
|
3668
3661
|
void remoteToken;
|
|
3669
3662
|
return false;
|
|
3670
3663
|
}
|
|
3664
|
+
function mergeNametagsByName(local, remote) {
|
|
3665
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3666
|
+
for (const item of local) {
|
|
3667
|
+
if (item.name) seen.set(item.name, item);
|
|
3668
|
+
}
|
|
3669
|
+
for (const item of remote) {
|
|
3670
|
+
if (item.name && !seen.has(item.name)) {
|
|
3671
|
+
seen.set(item.name, item);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
return Array.from(seen.values());
|
|
3675
|
+
}
|
|
3671
3676
|
function mergeArrayById(local, remote, idField) {
|
|
3672
3677
|
const seen = /* @__PURE__ */ new Map();
|
|
3673
3678
|
for (const item of local) {
|
|
@@ -4022,14 +4027,11 @@ var AsyncSerialQueue = class {
|
|
|
4022
4027
|
var WriteBuffer = class {
|
|
4023
4028
|
/** Full TXF data from save() calls — latest wins */
|
|
4024
4029
|
txfData = null;
|
|
4025
|
-
/** Individual token mutations: key -> { op: 'save'|'delete', data? } */
|
|
4026
|
-
tokenMutations = /* @__PURE__ */ new Map();
|
|
4027
4030
|
get isEmpty() {
|
|
4028
|
-
return this.txfData === null
|
|
4031
|
+
return this.txfData === null;
|
|
4029
4032
|
}
|
|
4030
4033
|
clear() {
|
|
4031
4034
|
this.txfData = null;
|
|
4032
|
-
this.tokenMutations.clear();
|
|
4033
4035
|
}
|
|
4034
4036
|
/**
|
|
4035
4037
|
* Merge another buffer's contents into this one (for rollback).
|
|
@@ -4039,11 +4041,6 @@ var WriteBuffer = class {
|
|
|
4039
4041
|
if (other.txfData && !this.txfData) {
|
|
4040
4042
|
this.txfData = other.txfData;
|
|
4041
4043
|
}
|
|
4042
|
-
for (const [id, mutation] of other.tokenMutations) {
|
|
4043
|
-
if (!this.tokenMutations.has(id)) {
|
|
4044
|
-
this.tokenMutations.set(id, mutation);
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
4044
|
}
|
|
4048
4045
|
};
|
|
4049
4046
|
|
|
@@ -4083,9 +4080,6 @@ var IpfsStorageProvider = class {
|
|
|
4083
4080
|
subscriptionClient = null;
|
|
4084
4081
|
/** Unsubscribe function from subscription client */
|
|
4085
4082
|
subscriptionUnsubscribe = null;
|
|
4086
|
-
/** In-memory buffer for individual token save/delete calls */
|
|
4087
|
-
tokenBuffer = /* @__PURE__ */ new Map();
|
|
4088
|
-
deletedTokenIds = /* @__PURE__ */ new Set();
|
|
4089
4083
|
/** Write-behind buffer: serializes flush / sync / shutdown */
|
|
4090
4084
|
flushQueue = new AsyncSerialQueue();
|
|
4091
4085
|
/** Pending mutations not yet flushed to IPFS */
|
|
@@ -4274,14 +4268,6 @@ var IpfsStorageProvider = class {
|
|
|
4274
4268
|
metaUpdate.lastCid = this.remoteCid;
|
|
4275
4269
|
}
|
|
4276
4270
|
const updatedData = { ...data, _meta: metaUpdate };
|
|
4277
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4278
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4279
|
-
updatedData[tokenId] = tokenData;
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
for (const tokenId of this.deletedTokenIds) {
|
|
4283
|
-
delete updatedData[tokenId];
|
|
4284
|
-
}
|
|
4285
4271
|
const { cid } = await this.httpClient.upload(updatedData);
|
|
4286
4272
|
this.log(`Content uploaded: CID=${cid}`);
|
|
4287
4273
|
const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence ? this.ipnsSequenceNumber : this.lastKnownRemoteSequence;
|
|
@@ -4320,7 +4306,6 @@ var IpfsStorageProvider = class {
|
|
|
4320
4306
|
lastCid: cid,
|
|
4321
4307
|
version: this.dataVersion
|
|
4322
4308
|
});
|
|
4323
|
-
this.deletedTokenIds.clear();
|
|
4324
4309
|
this.emitEvent({
|
|
4325
4310
|
type: "storage:saved",
|
|
4326
4311
|
timestamp: Date.now(),
|
|
@@ -4432,7 +4417,6 @@ var IpfsStorageProvider = class {
|
|
|
4432
4417
|
if (typeof remoteVersion === "number" && remoteVersion > this.dataVersion) {
|
|
4433
4418
|
this.dataVersion = remoteVersion;
|
|
4434
4419
|
}
|
|
4435
|
-
this.populateTokenBuffer(data);
|
|
4436
4420
|
this.emitEvent({
|
|
4437
4421
|
type: "storage:loaded",
|
|
4438
4422
|
timestamp: Date.now(),
|
|
@@ -4478,7 +4462,7 @@ var IpfsStorageProvider = class {
|
|
|
4478
4462
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4479
4463
|
return {
|
|
4480
4464
|
success: saveResult2.success,
|
|
4481
|
-
merged:
|
|
4465
|
+
merged: localData,
|
|
4482
4466
|
added: 0,
|
|
4483
4467
|
removed: 0,
|
|
4484
4468
|
conflicts: 0,
|
|
@@ -4493,7 +4477,7 @@ var IpfsStorageProvider = class {
|
|
|
4493
4477
|
this.emitEvent({ type: "sync:completed", timestamp: Date.now() });
|
|
4494
4478
|
return {
|
|
4495
4479
|
success: true,
|
|
4496
|
-
merged:
|
|
4480
|
+
merged: localData,
|
|
4497
4481
|
added: 0,
|
|
4498
4482
|
removed: 0,
|
|
4499
4483
|
conflicts: 0
|
|
@@ -4516,7 +4500,7 @@ var IpfsStorageProvider = class {
|
|
|
4516
4500
|
});
|
|
4517
4501
|
return {
|
|
4518
4502
|
success: saveResult.success,
|
|
4519
|
-
merged
|
|
4503
|
+
merged,
|
|
4520
4504
|
added,
|
|
4521
4505
|
removed,
|
|
4522
4506
|
conflicts,
|
|
@@ -4542,21 +4526,6 @@ var IpfsStorageProvider = class {
|
|
|
4542
4526
|
// ---------------------------------------------------------------------------
|
|
4543
4527
|
// Private Helpers
|
|
4544
4528
|
// ---------------------------------------------------------------------------
|
|
4545
|
-
/**
|
|
4546
|
-
* Enrich TXF data with individually-buffered tokens before returning to caller.
|
|
4547
|
-
* PaymentsModule.createStorageData() passes empty tokens (they're stored via
|
|
4548
|
-
* saveToken()), but loadFromStorageData() needs them in the merged result.
|
|
4549
|
-
*/
|
|
4550
|
-
enrichWithTokenBuffer(data) {
|
|
4551
|
-
if (this.tokenBuffer.size === 0) return data;
|
|
4552
|
-
const enriched = { ...data };
|
|
4553
|
-
for (const [tokenId, tokenData] of this.tokenBuffer) {
|
|
4554
|
-
if (!this.deletedTokenIds.has(tokenId)) {
|
|
4555
|
-
enriched[tokenId] = tokenData;
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
return enriched;
|
|
4559
|
-
}
|
|
4560
4529
|
// ---------------------------------------------------------------------------
|
|
4561
4530
|
// Optional Methods
|
|
4562
4531
|
// ---------------------------------------------------------------------------
|
|
@@ -4586,8 +4555,6 @@ var IpfsStorageProvider = class {
|
|
|
4586
4555
|
const result = await this._doSave(emptyData);
|
|
4587
4556
|
if (result.success) {
|
|
4588
4557
|
this.cache.clear();
|
|
4589
|
-
this.tokenBuffer.clear();
|
|
4590
|
-
this.deletedTokenIds.clear();
|
|
4591
4558
|
await this.statePersistence.clear(this.ipnsName);
|
|
4592
4559
|
}
|
|
4593
4560
|
return result.success;
|
|
@@ -4598,27 +4565,6 @@ var IpfsStorageProvider = class {
|
|
|
4598
4565
|
this.eventCallbacks.delete(callback);
|
|
4599
4566
|
};
|
|
4600
4567
|
}
|
|
4601
|
-
async saveToken(tokenId, tokenData) {
|
|
4602
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "save", data: tokenData });
|
|
4603
|
-
this.tokenBuffer.set(tokenId, tokenData);
|
|
4604
|
-
this.deletedTokenIds.delete(tokenId);
|
|
4605
|
-
this.scheduleFlush();
|
|
4606
|
-
}
|
|
4607
|
-
async getToken(tokenId) {
|
|
4608
|
-
if (this.deletedTokenIds.has(tokenId)) return null;
|
|
4609
|
-
return this.tokenBuffer.get(tokenId) ?? null;
|
|
4610
|
-
}
|
|
4611
|
-
async listTokenIds() {
|
|
4612
|
-
return Array.from(this.tokenBuffer.keys()).filter(
|
|
4613
|
-
(id) => !this.deletedTokenIds.has(id)
|
|
4614
|
-
);
|
|
4615
|
-
}
|
|
4616
|
-
async deleteToken(tokenId) {
|
|
4617
|
-
this.pendingBuffer.tokenMutations.set(tokenId, { op: "delete" });
|
|
4618
|
-
this.tokenBuffer.delete(tokenId);
|
|
4619
|
-
this.deletedTokenIds.add(tokenId);
|
|
4620
|
-
this.scheduleFlush();
|
|
4621
|
-
}
|
|
4622
4568
|
// ---------------------------------------------------------------------------
|
|
4623
4569
|
// Public Accessors
|
|
4624
4570
|
// ---------------------------------------------------------------------------
|
|
@@ -4710,26 +4656,6 @@ var IpfsStorageProvider = class {
|
|
|
4710
4656
|
console.log(`[IPFS-Storage] ${message}`);
|
|
4711
4657
|
}
|
|
4712
4658
|
}
|
|
4713
|
-
META_KEYS = /* @__PURE__ */ new Set([
|
|
4714
|
-
"_meta",
|
|
4715
|
-
"_tombstones",
|
|
4716
|
-
"_outbox",
|
|
4717
|
-
"_sent",
|
|
4718
|
-
"_invalid",
|
|
4719
|
-
"_nametag",
|
|
4720
|
-
"_mintOutbox",
|
|
4721
|
-
"_invalidatedNametags",
|
|
4722
|
-
"_integrity"
|
|
4723
|
-
]);
|
|
4724
|
-
populateTokenBuffer(data) {
|
|
4725
|
-
this.tokenBuffer.clear();
|
|
4726
|
-
this.deletedTokenIds.clear();
|
|
4727
|
-
for (const key of Object.keys(data)) {
|
|
4728
|
-
if (!this.META_KEYS.has(key)) {
|
|
4729
|
-
this.tokenBuffer.set(key, data[key]);
|
|
4730
|
-
}
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
4659
|
};
|
|
4734
4660
|
|
|
4735
4661
|
// impl/nodejs/ipfs/nodejs-ipfs-state-persistence.ts
|
|
@@ -4955,6 +4881,20 @@ function resolvePriceConfig(config) {
|
|
|
4955
4881
|
debug: config.debug
|
|
4956
4882
|
};
|
|
4957
4883
|
}
|
|
4884
|
+
function resolveGroupChatConfig(network, config) {
|
|
4885
|
+
if (!config) return void 0;
|
|
4886
|
+
if (config === true) {
|
|
4887
|
+
const netConfig2 = getNetworkConfig(network);
|
|
4888
|
+
return { relays: [...netConfig2.groupRelays] };
|
|
4889
|
+
}
|
|
4890
|
+
if (typeof config === "object" && config.enabled === false) {
|
|
4891
|
+
return void 0;
|
|
4892
|
+
}
|
|
4893
|
+
const netConfig = getNetworkConfig(network);
|
|
4894
|
+
return {
|
|
4895
|
+
relays: config.relays ?? [...netConfig.groupRelays]
|
|
4896
|
+
};
|
|
4897
|
+
}
|
|
4958
4898
|
|
|
4959
4899
|
// impl/nodejs/index.ts
|
|
4960
4900
|
function createNodeProviders(config) {
|
|
@@ -4968,8 +4908,10 @@ function createNodeProviders(config) {
|
|
|
4968
4908
|
});
|
|
4969
4909
|
const ipfsSync = config?.tokenSync?.ipfs;
|
|
4970
4910
|
const ipfsTokenStorage = ipfsSync?.enabled ? createNodeIpfsStorageProvider(ipfsSync.config, storage) : void 0;
|
|
4911
|
+
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
4971
4912
|
return {
|
|
4972
4913
|
storage,
|
|
4914
|
+
groupChat,
|
|
4973
4915
|
tokenStorage: createFileTokenStorageProvider({
|
|
4974
4916
|
tokensDir: config?.tokensDir ?? "./sphere-tokens"
|
|
4975
4917
|
}),
|