@unicitylabs/sphere-sdk 0.6.4 → 0.6.6

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.
@@ -2312,6 +2312,7 @@ declare class PaymentsModule {
2312
2312
  private pendingTransfers;
2313
2313
  private pendingBackgroundTasks;
2314
2314
  private tombstones;
2315
+ private tombstoneKeySet;
2315
2316
  private archivedTokens;
2316
2317
  private forkedTokens;
2317
2318
  private _historyCache;
@@ -2762,12 +2763,14 @@ declare class PaymentsModule {
2762
2763
  getTombstones(): TombstoneEntry[];
2763
2764
  /**
2764
2765
  * Check whether a specific `(tokenId, stateHash)` combination is tombstoned.
2766
+ * Uses O(1) Set lookup instead of O(n) linear scan.
2765
2767
  *
2766
2768
  * @param tokenId - The genesis token ID.
2767
2769
  * @param stateHash - The state hash of the token version to check.
2768
2770
  * @returns `true` if the exact combination has been tombstoned.
2769
2771
  */
2770
2772
  isStateTombstoned(tokenId: string, stateHash: string): boolean;
2773
+ private rebuildTombstoneKeySet;
2771
2774
  /**
2772
2775
  * Merge tombstones received from a remote sync source.
2773
2776
  *
@@ -2312,6 +2312,7 @@ declare class PaymentsModule {
2312
2312
  private pendingTransfers;
2313
2313
  private pendingBackgroundTasks;
2314
2314
  private tombstones;
2315
+ private tombstoneKeySet;
2315
2316
  private archivedTokens;
2316
2317
  private forkedTokens;
2317
2318
  private _historyCache;
@@ -2762,12 +2763,14 @@ declare class PaymentsModule {
2762
2763
  getTombstones(): TombstoneEntry[];
2763
2764
  /**
2764
2765
  * Check whether a specific `(tokenId, stateHash)` combination is tombstoned.
2766
+ * Uses O(1) Set lookup instead of O(n) linear scan.
2765
2767
  *
2766
2768
  * @param tokenId - The genesis token ID.
2767
2769
  * @param stateHash - The state hash of the token version to check.
2768
2770
  * @returns `true` if the exact combination has been tombstoned.
2769
2771
  */
2770
2772
  isStateTombstoned(tokenId: string, stateHash: string): boolean;
2773
+ private rebuildTombstoneKeySet;
2771
2774
  /**
2772
2775
  * Merge tombstones received from a remote sync source.
2773
2776
  *
@@ -6260,7 +6260,7 @@ function normalizeToHex(value) {
6260
6260
  return String(value);
6261
6261
  }
6262
6262
  function normalizeSdkTokenToStorage(sdkTokenJson) {
6263
- const txf = JSON.parse(JSON.stringify(sdkTokenJson));
6263
+ const txf = structuredClone(sdkTokenJson);
6264
6264
  if (txf.genesis?.data) {
6265
6265
  const data = txf.genesis.data;
6266
6266
  if (data.tokenId !== void 0) {
@@ -7490,35 +7490,45 @@ async function parseTokenInfo(tokenData) {
7490
7490
  }
7491
7491
  return defaultInfo;
7492
7492
  }
7493
- function extractTokenIdFromSdkData(sdkData) {
7494
- if (!sdkData) return null;
7495
- try {
7496
- const txf = JSON.parse(sdkData);
7497
- return txf.genesis?.data?.tokenId || null;
7498
- } catch {
7499
- return null;
7500
- }
7501
- }
7502
- function extractStateHashFromSdkData(sdkData) {
7503
- if (!sdkData) return "";
7493
+ var sdkDataCache = /* @__PURE__ */ new Map();
7494
+ var SDK_DATA_CACHE_MAX = 2e3;
7495
+ function parseSdkDataCached(sdkData) {
7496
+ const cached = sdkDataCache.get(sdkData);
7497
+ if (cached) return cached;
7498
+ let tokenId = null;
7499
+ let stateHash = "";
7504
7500
  try {
7505
7501
  const txf = JSON.parse(sdkData);
7506
- const stateHash = getCurrentStateHash(txf);
7502
+ tokenId = txf.genesis?.data?.tokenId || null;
7503
+ stateHash = getCurrentStateHash(txf) || "";
7507
7504
  if (!stateHash) {
7508
7505
  if (txf.state?.hash) {
7509
- return txf.state.hash;
7510
- }
7511
- if (txf.stateHash) {
7512
- return txf.stateHash;
7513
- }
7514
- if (txf.currentStateHash) {
7515
- return txf.currentStateHash;
7506
+ stateHash = txf.state.hash;
7507
+ } else if (txf.stateHash) {
7508
+ stateHash = txf.stateHash;
7509
+ } else if (txf.currentStateHash) {
7510
+ stateHash = txf.currentStateHash;
7516
7511
  }
7517
7512
  }
7518
- return stateHash || "";
7519
7513
  } catch {
7520
- return "";
7521
7514
  }
7515
+ const entry = { tokenId, stateHash };
7516
+ if (sdkDataCache.size >= SDK_DATA_CACHE_MAX) {
7517
+ sdkDataCache.clear();
7518
+ }
7519
+ sdkDataCache.set(sdkData, entry);
7520
+ return entry;
7521
+ }
7522
+ function clearSdkDataCache() {
7523
+ sdkDataCache.clear();
7524
+ }
7525
+ function extractTokenIdFromSdkData(sdkData) {
7526
+ if (!sdkData) return null;
7527
+ return parseSdkDataCached(sdkData).tokenId;
7528
+ }
7529
+ function extractStateHashFromSdkData(sdkData) {
7530
+ if (!sdkData) return "";
7531
+ return parseSdkDataCached(sdkData).stateHash;
7522
7532
  }
7523
7533
  function createTokenStateKey(tokenId, stateHash) {
7524
7534
  return `${tokenId}_${stateHash}`;
@@ -7628,6 +7638,8 @@ var PaymentsModule = class _PaymentsModule {
7628
7638
  pendingBackgroundTasks = [];
7629
7639
  // Repository State (tombstones, archives, forked, history)
7630
7640
  tombstones = [];
7641
+ // O(1) lookup set derived from tombstones array. Rebuilt via rebuildTombstoneKeySet().
7642
+ tombstoneKeySet = /* @__PURE__ */ new Set();
7631
7643
  archivedTokens = /* @__PURE__ */ new Map();
7632
7644
  forkedTokens = /* @__PURE__ */ new Map();
7633
7645
  _historyCache = [];
@@ -7712,8 +7724,10 @@ var PaymentsModule = class _PaymentsModule {
7712
7724
  }
7713
7725
  this.pendingResponseResolvers.clear();
7714
7726
  this.tokens.clear();
7727
+ clearSdkDataCache();
7715
7728
  this.pendingTransfers.clear();
7716
7729
  this.tombstones = [];
7730
+ this.tombstoneKeySet.clear();
7717
7731
  this.archivedTokens.clear();
7718
7732
  this.forkedTokens.clear();
7719
7733
  this._historyCache = [];
@@ -9834,11 +9848,10 @@ var PaymentsModule = class _PaymentsModule {
9834
9848
  await this.archiveToken(token);
9835
9849
  const tombstone = createTombstoneFromToken(token);
9836
9850
  if (tombstone) {
9837
- const alreadyTombstoned = this.tombstones.some(
9838
- (t) => t.tokenId === tombstone.tokenId && t.stateHash === tombstone.stateHash
9839
- );
9840
- if (!alreadyTombstoned) {
9851
+ const key = `${tombstone.tokenId}:${tombstone.stateHash}`;
9852
+ if (!this.tombstoneKeySet.has(key)) {
9841
9853
  this.tombstones.push(tombstone);
9854
+ this.tombstoneKeySet.add(key);
9842
9855
  logger.debug("Payments", `Created tombstone for ${tombstone.tokenId.slice(0, 8)}..._${tombstone.stateHash.slice(0, 8)}...`);
9843
9856
  }
9844
9857
  } else {
@@ -9863,15 +9876,20 @@ var PaymentsModule = class _PaymentsModule {
9863
9876
  }
9864
9877
  /**
9865
9878
  * Check whether a specific `(tokenId, stateHash)` combination is tombstoned.
9879
+ * Uses O(1) Set lookup instead of O(n) linear scan.
9866
9880
  *
9867
9881
  * @param tokenId - The genesis token ID.
9868
9882
  * @param stateHash - The state hash of the token version to check.
9869
9883
  * @returns `true` if the exact combination has been tombstoned.
9870
9884
  */
9871
9885
  isStateTombstoned(tokenId, stateHash) {
9872
- return this.tombstones.some(
9873
- (t) => t.tokenId === tokenId && t.stateHash === stateHash
9874
- );
9886
+ return this.tombstoneKeySet.has(`${tokenId}:${stateHash}`);
9887
+ }
9888
+ rebuildTombstoneKeySet() {
9889
+ this.tombstoneKeySet.clear();
9890
+ for (const t of this.tombstones) {
9891
+ this.tombstoneKeySet.add(`${t.tokenId}:${t.stateHash}`);
9892
+ }
9875
9893
  }
9876
9894
  /**
9877
9895
  * Merge tombstones received from a remote sync source.
@@ -9903,11 +9921,10 @@ var PaymentsModule = class _PaymentsModule {
9903
9921
  removedCount++;
9904
9922
  }
9905
9923
  for (const remoteTombstone of remoteTombstones) {
9906
- const alreadyExists = this.tombstones.some(
9907
- (t) => t.tokenId === remoteTombstone.tokenId && t.stateHash === remoteTombstone.stateHash
9908
- );
9909
- if (!alreadyExists) {
9924
+ const key = `${remoteTombstone.tokenId}:${remoteTombstone.stateHash}`;
9925
+ if (!this.tombstoneKeySet.has(key)) {
9910
9926
  this.tombstones.push(remoteTombstone);
9927
+ this.tombstoneKeySet.add(key);
9911
9928
  }
9912
9929
  }
9913
9930
  if (removedCount > 0) {
@@ -9923,6 +9940,7 @@ var PaymentsModule = class _PaymentsModule {
9923
9940
  async pruneTombstones(maxAge) {
9924
9941
  const originalCount = this.tombstones.length;
9925
9942
  this.tombstones = pruneTombstonesByAge(this.tombstones, maxAge);
9943
+ this.rebuildTombstoneKeySet();
9926
9944
  if (this.tombstones.length < originalCount) {
9927
9945
  await this.save();
9928
9946
  logger.debug("Payments", `Pruned tombstones from ${originalCount} to ${this.tombstones.length}`);
@@ -10409,6 +10427,11 @@ var PaymentsModule = class _PaymentsModule {
10409
10427
  }
10410
10428
  const savedTokens = new Map(this.tokens);
10411
10429
  this.loadFromStorageData(result.merged);
10430
+ const existingGenesisIds = /* @__PURE__ */ new Set();
10431
+ for (const existing of this.tokens.values()) {
10432
+ const gid = extractTokenIdFromSdkData(existing.sdkData);
10433
+ if (gid) existingGenesisIds.add(gid);
10434
+ }
10412
10435
  let restoredCount = 0;
10413
10436
  for (const [tokenId, token] of savedTokens) {
10414
10437
  if (this.tokens.has(tokenId)) continue;
@@ -10417,17 +10440,11 @@ var PaymentsModule = class _PaymentsModule {
10417
10440
  if (sdkTokenId && stateHash && this.isStateTombstoned(sdkTokenId, stateHash)) {
10418
10441
  continue;
10419
10442
  }
10420
- if (sdkTokenId) {
10421
- let hasEquivalent = false;
10422
- for (const existing of this.tokens.values()) {
10423
- if (extractTokenIdFromSdkData(existing.sdkData) === sdkTokenId) {
10424
- hasEquivalent = true;
10425
- break;
10426
- }
10427
- }
10428
- if (hasEquivalent) continue;
10443
+ if (sdkTokenId && existingGenesisIds.has(sdkTokenId)) {
10444
+ continue;
10429
10445
  }
10430
10446
  this.tokens.set(tokenId, token);
10447
+ if (sdkTokenId) existingGenesisIds.add(sdkTokenId);
10431
10448
  restoredCount++;
10432
10449
  }
10433
10450
  if (restoredCount > 0) {
@@ -11174,6 +11191,7 @@ var PaymentsModule = class _PaymentsModule {
11174
11191
  const parsed = parseTxfStorageData(data);
11175
11192
  logger.debug("Payments", `loadFromStorageData: parsed ${parsed.tokens.length} tokens, ${parsed.tombstones.length} tombstones, errors=[${parsed.validationErrors.join("; ")}]`);
11176
11193
  this.tombstones = parsed.tombstones;
11194
+ this.rebuildTombstoneKeySet();
11177
11195
  this.tokens.clear();
11178
11196
  for (const token of parsed.tokens) {
11179
11197
  const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);
@@ -17818,9 +17836,16 @@ var Sphere = class _Sphere {
17818
17836
  emitEvent
17819
17837
  });
17820
17838
  await payments.load();
17821
- await communications.load();
17822
- await groupChat?.load();
17823
- await market?.load();
17839
+ const results = await Promise.allSettled([
17840
+ communications.load(),
17841
+ groupChat?.load(),
17842
+ market?.load()
17843
+ ]);
17844
+ for (const r of results) {
17845
+ if (r.status === "rejected") {
17846
+ logger.warn("Sphere", "Module load failed:", r.reason);
17847
+ }
17848
+ }
17824
17849
  const moduleSet = {
17825
17850
  index,
17826
17851
  identity,
@@ -19035,9 +19060,9 @@ var Sphere = class _Sphere {
19035
19060
  await this._transport.connect();
19036
19061
  }
19037
19062
  await this._oracle.initialize();
19038
- for (const provider of this._tokenStorageProviders.values()) {
19039
- await provider.initialize();
19040
- }
19063
+ await Promise.all(
19064
+ [...this._tokenStorageProviders.values()].map((p) => p.initialize())
19065
+ );
19041
19066
  this.subscribeToProviderEvents();
19042
19067
  }
19043
19068
  /**
@@ -19143,10 +19168,17 @@ var Sphere = class _Sphere {
19143
19168
  identity: this._identity,
19144
19169
  emitEvent
19145
19170
  });
19146
- await this._payments.load();
19147
- await this._communications.load();
19148
- await this._groupChat?.load();
19149
- await this._market?.load();
19171
+ const results = await Promise.allSettled([
19172
+ this._payments.load(),
19173
+ this._communications.load(),
19174
+ this._groupChat?.load(),
19175
+ this._market?.load()
19176
+ ]);
19177
+ for (const r of results) {
19178
+ if (r.status === "rejected") {
19179
+ logger.warn("Sphere", "Module load failed:", r.reason);
19180
+ }
19181
+ }
19150
19182
  this._addressModules.set(this._currentAddressIndex, {
19151
19183
  index: this._currentAddressIndex,
19152
19184
  identity: this._identity,