@unicitylabs/sphere-sdk 0.13.2-dev.1 → 0.13.2-dev.2

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.
@@ -1490,8 +1490,9 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1490
1490
  createForAddress?(sharedClient?: unknown): TokenStorageProvider<TData>;
1491
1491
  /**
1492
1492
  * Subscribe to storage events
1493
- */
1494
- onEvent?(callback: StorageEventCallback): () => void;
1493
+
1494
+ // --- History operations (optional — not supported by all providers, e.g. IPFS) ---
1495
+
1495
1496
  /** Store a history entry (upsert by dedupKey) */
1496
1497
  addHistoryEntry?(entry: HistoryRecord): Promise<void>;
1497
1498
  /** Get all history entries sorted by timestamp descending */
@@ -1503,14 +1504,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1503
1504
  /** Bulk import history entries (skip existing dedupKeys). Returns count of newly imported. */
1504
1505
  importHistoryEntries?(entries: HistoryRecord[]): Promise<number>;
1505
1506
  }
1506
- type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
1507
- interface StorageEvent {
1508
- type: StorageEventType;
1509
- timestamp: number;
1510
- data?: unknown;
1511
- error?: string;
1512
- }
1513
- type StorageEventCallback = (event: StorageEvent) => void;
1514
1507
  interface TxfStorageDataBase {
1515
1508
  _meta: TxfMeta;
1516
1509
  _tombstones?: TxfTombstone[];
@@ -1490,8 +1490,9 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1490
1490
  createForAddress?(sharedClient?: unknown): TokenStorageProvider<TData>;
1491
1491
  /**
1492
1492
  * Subscribe to storage events
1493
- */
1494
- onEvent?(callback: StorageEventCallback): () => void;
1493
+
1494
+ // --- History operations (optional — not supported by all providers, e.g. IPFS) ---
1495
+
1495
1496
  /** Store a history entry (upsert by dedupKey) */
1496
1497
  addHistoryEntry?(entry: HistoryRecord): Promise<void>;
1497
1498
  /** Get all history entries sorted by timestamp descending */
@@ -1503,14 +1504,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1503
1504
  /** Bulk import history entries (skip existing dedupKeys). Returns count of newly imported. */
1504
1505
  importHistoryEntries?(entries: HistoryRecord[]): Promise<number>;
1505
1506
  }
1506
- type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
1507
- interface StorageEvent {
1508
- type: StorageEventType;
1509
- timestamp: number;
1510
- data?: unknown;
1511
- error?: string;
1512
- }
1513
- type StorageEventCallback = (event: StorageEvent) => void;
1514
1507
  interface TxfStorageDataBase {
1515
1508
  _meta: TxfMeta;
1516
1509
  _tombstones?: TxfTombstone[];
@@ -1025,8 +1025,9 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1025
1025
  createForAddress?(sharedClient?: unknown): TokenStorageProvider<TData>;
1026
1026
  /**
1027
1027
  * Subscribe to storage events
1028
- */
1029
- onEvent?(callback: StorageEventCallback): () => void;
1028
+
1029
+ // --- History operations (optional — not supported by all providers, e.g. IPFS) ---
1030
+
1030
1031
  /** Store a history entry (upsert by dedupKey) */
1031
1032
  addHistoryEntry?(entry: HistoryRecord): Promise<void>;
1032
1033
  /** Get all history entries sorted by timestamp descending */
@@ -1038,14 +1039,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1038
1039
  /** Bulk import history entries (skip existing dedupKeys). Returns count of newly imported. */
1039
1040
  importHistoryEntries?(entries: HistoryRecord[]): Promise<number>;
1040
1041
  }
1041
- type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
1042
- interface StorageEvent {
1043
- type: StorageEventType;
1044
- timestamp: number;
1045
- data?: unknown;
1046
- error?: string;
1047
- }
1048
- type StorageEventCallback = (event: StorageEvent) => void;
1049
1042
  interface TxfStorageDataBase {
1050
1043
  _meta: TxfMeta;
1051
1044
  _tombstones?: TxfTombstone[];
@@ -1025,8 +1025,9 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1025
1025
  createForAddress?(sharedClient?: unknown): TokenStorageProvider<TData>;
1026
1026
  /**
1027
1027
  * Subscribe to storage events
1028
- */
1029
- onEvent?(callback: StorageEventCallback): () => void;
1028
+
1029
+ // --- History operations (optional — not supported by all providers, e.g. IPFS) ---
1030
+
1030
1031
  /** Store a history entry (upsert by dedupKey) */
1031
1032
  addHistoryEntry?(entry: HistoryRecord): Promise<void>;
1032
1033
  /** Get all history entries sorted by timestamp descending */
@@ -1038,14 +1039,6 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1038
1039
  /** Bulk import history entries (skip existing dedupKeys). Returns count of newly imported. */
1039
1040
  importHistoryEntries?(entries: HistoryRecord[]): Promise<number>;
1040
1041
  }
1041
- type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
1042
- interface StorageEvent {
1043
- type: StorageEventType;
1044
- timestamp: number;
1045
- data?: unknown;
1046
- error?: string;
1047
- }
1048
- type StorageEventCallback = (event: StorageEvent) => void;
1049
1042
  interface TxfStorageDataBase {
1050
1043
  _meta: TxfMeta;
1051
1044
  _tombstones?: TxfTombstone[];
package/dist/index.cjs CHANGED
@@ -11783,8 +11783,7 @@ var PaymentsModule = class _PaymentsModule {
11783
11783
  incrementalHistoryPulls = 0;
11784
11784
  hydrationEpoch = 0;
11785
11785
  // Storage event subscriptions (push-based sync)
11786
- storageEventUnsubscribers = [];
11787
- syncDebounceTimer = null;
11786
+ inventoryDebounceTimer = null;
11788
11787
  static SYNC_DEBOUNCE_MS = 500;
11789
11788
  /** Quiet-then-escalate logging for the background wallet-api pumps (#630). */
11790
11789
  pumpHealth = new PumpHealth();
@@ -11909,7 +11908,6 @@ var PaymentsModule = class _PaymentsModule {
11909
11908
  assertLegalCustodyComposition(deps);
11910
11909
  this.teardownDeliveryPump();
11911
11910
  this.teardownPaymentRequestPump();
11912
- this.unsubscribeStorageEvents();
11913
11911
  for (const [, resolver] of this.pendingResponseResolvers) {
11914
11912
  clearTimeout(resolver.timeout);
11915
11913
  resolver.reject(new Error("Address switched"));
@@ -11978,7 +11976,6 @@ var PaymentsModule = class _PaymentsModule {
11978
11976
  this.pumpHealth.run("payment-requests", () => this.pumpPaymentRequests());
11979
11977
  }, DELIVERY_POLL_INTERVAL_MS);
11980
11978
  }
11981
- this.subscribeToStorageEvents();
11982
11979
  }
11983
11980
  /**
11984
11981
  * Load all token data from storage providers and restore wallet state.
@@ -12151,7 +12148,6 @@ var PaymentsModule = class _PaymentsModule {
12151
12148
  this.reservationLedger.clear();
12152
12149
  this.parsedTokenCache.clear();
12153
12150
  this.tokens.clear();
12154
- this.unsubscribeStorageEvents();
12155
12151
  }
12156
12152
  // ===========================================================================
12157
12153
  // Public API - Send
@@ -14145,115 +14141,29 @@ var PaymentsModule = class _PaymentsModule {
14145
14141
  // Public API - Sync & Validate
14146
14142
  // ===========================================================================
14147
14143
  /**
14148
- * Sync local token state with all configured token storage providers (IPFS, file, etc.).
14144
+ * Flush local token state to every configured token storage provider.
14149
14145
  *
14150
- * For each provider, the local data is packaged into TXF storage format, sent
14151
- * to the provider's `sync()` method, and the merged result is applied locally.
14152
- * Emits `sync:started`, `sync:completed`, and `sync:error` events.
14153
- *
14154
- * @returns Summary with counts of tokens added and removed during sync.
14146
+ * Named `sync` for history: it once merged remote TXF state back in, which
14147
+ * only IPFS ever supplied. The remaining providers all implement `sync()` as
14148
+ * "save and return the input unchanged", so this is a write, and the returned
14149
+ * counts are always zero.
14155
14150
  */
14156
14151
  async sync() {
14157
14152
  this.ensureInitialized();
14158
- if (this._syncInProgress) {
14159
- return this._syncInProgress;
14160
- }
14161
- this._syncInProgress = this._doSync();
14153
+ if (this._syncInProgress) return this._syncInProgress;
14154
+ this._syncInProgress = this._doFlush();
14162
14155
  try {
14163
14156
  return await this._syncInProgress;
14164
14157
  } finally {
14165
14158
  this._syncInProgress = null;
14166
14159
  }
14167
14160
  }
14168
- async _doSync() {
14161
+ async _doFlush() {
14169
14162
  this.deps.emitEvent("sync:started", { source: "payments" });
14170
14163
  try {
14171
- const providers = this.getTokenStorageProviders();
14172
- if (providers.size === 0) {
14173
- await this.save();
14174
- this.deps.emitEvent("sync:completed", {
14175
- source: "payments",
14176
- count: this.tokens.size
14177
- });
14178
- return { added: 0, removed: 0 };
14179
- }
14180
- const localData = await this.createStorageData();
14181
- let totalAdded = 0;
14182
- let totalRemoved = 0;
14183
- const savedNametags = [...this.nametags];
14184
- for (const [providerId, provider] of providers) {
14185
- try {
14186
- const result = await provider.sync(localData);
14187
- if (result.success && result.merged) {
14188
- const mergedMeta = result.merged?._meta;
14189
- const currentChain = this.deps.identity.chainPubkey;
14190
- const isLegacyAlpha = mergedMeta?.address?.startsWith("alpha1") ?? false;
14191
- if (mergedMeta?.address && currentChain && !isLegacyAlpha && mergedMeta.address !== currentChain) {
14192
- logger.warn("Payments", `Sync: rejecting data from provider ${providerId} \u2014 address mismatch (got=${mergedMeta.address.slice(0, 20)}... expected=${currentChain.slice(0, 20)}...)`);
14193
- continue;
14194
- }
14195
- const savedTokens = new Map(this.tokens);
14196
- this.loadFromStorageData(result.merged);
14197
- const existingGenesisIds = /* @__PURE__ */ new Set();
14198
- for (const existing of this.tokens.values()) {
14199
- const gid = extractTokenIdFromSdkData(existing.sdkData);
14200
- if (gid) existingGenesisIds.add(gid);
14201
- }
14202
- let restoredCount = 0;
14203
- for (const [tokenId, token] of savedTokens) {
14204
- if (this.tokens.has(tokenId)) continue;
14205
- const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);
14206
- const stateHash = extractStateHashFromSdkData(token.sdkData);
14207
- if (sdkTokenId && stateHash && this.isStateTombstoned(sdkTokenId, stateHash)) {
14208
- continue;
14209
- }
14210
- if (sdkTokenId && existingGenesisIds.has(sdkTokenId)) {
14211
- continue;
14212
- }
14213
- this.tokens.set(tokenId, token);
14214
- if (sdkTokenId) existingGenesisIds.add(sdkTokenId);
14215
- restoredCount++;
14216
- }
14217
- if (restoredCount > 0) {
14218
- logger.debug("Payments", `Sync: restored ${restoredCount} token(s) lost by loadFromStorageData`);
14219
- }
14220
- if (this.nametags.length === 0 && savedNametags.length > 0) {
14221
- this.nametags = savedNametags;
14222
- }
14223
- await this.rebuildParsedTokenCache();
14224
- const txfData = result.merged;
14225
- if (txfData._history && txfData._history.length > 0) {
14226
- const imported = await this.importRemoteHistoryEntries(txfData._history);
14227
- if (imported > 0) {
14228
- logger.debug("Payments", `Imported ${imported} history entries from IPFS sync`);
14229
- }
14230
- }
14231
- totalAdded += result.added;
14232
- totalRemoved += result.removed;
14233
- }
14234
- this.deps.emitEvent("sync:provider", {
14235
- providerId,
14236
- success: result.success,
14237
- added: result.added,
14238
- removed: result.removed
14239
- });
14240
- } catch (providerError) {
14241
- logger.warn("Payments", `Sync failed for provider ${providerId}:`, providerError);
14242
- this.deps.emitEvent("sync:provider", {
14243
- providerId,
14244
- success: false,
14245
- error: providerError instanceof Error ? providerError.message : String(providerError)
14246
- });
14247
- }
14248
- }
14249
- if (totalAdded > 0 || totalRemoved > 0) {
14250
- await this.save();
14251
- }
14252
- this.deps.emitEvent("sync:completed", {
14253
- source: "payments",
14254
- count: this.tokens.size
14255
- });
14256
- return { added: totalAdded, removed: totalRemoved };
14164
+ await this.save();
14165
+ this.deps.emitEvent("sync:completed", { source: "payments", count: this.tokens.size });
14166
+ return { added: 0, removed: 0 };
14257
14167
  } catch (error) {
14258
14168
  this.deps.emitEvent("sync:error", {
14259
14169
  source: "payments",
@@ -14262,66 +14172,6 @@ var PaymentsModule = class _PaymentsModule {
14262
14172
  throw error;
14263
14173
  }
14264
14174
  }
14265
- // ===========================================================================
14266
- // Storage Event Subscription (Push-Based Sync)
14267
- // ===========================================================================
14268
- /**
14269
- * Subscribe to 'storage:remote-updated' events from all token storage providers.
14270
- * When a provider emits this event, a debounced sync is triggered.
14271
- */
14272
- subscribeToStorageEvents() {
14273
- this.unsubscribeStorageEvents();
14274
- const providers = this.getTokenStorageProviders();
14275
- for (const [providerId, provider] of providers) {
14276
- if (provider.onEvent) {
14277
- const unsub = provider.onEvent((event) => {
14278
- if (event.type === "storage:remote-updated") {
14279
- logger.debug("Payments", "Remote update detected from provider", providerId, event.data);
14280
- this.debouncedSyncFromRemoteUpdate(providerId, event.data);
14281
- }
14282
- });
14283
- this.storageEventUnsubscribers.push(unsub);
14284
- }
14285
- }
14286
- }
14287
- /**
14288
- * Unsubscribe from all storage provider events and clear debounce timer.
14289
- */
14290
- unsubscribeStorageEvents() {
14291
- for (const unsub of this.storageEventUnsubscribers) {
14292
- unsub();
14293
- }
14294
- this.storageEventUnsubscribers = [];
14295
- if (this.syncDebounceTimer) {
14296
- clearTimeout(this.syncDebounceTimer);
14297
- this.syncDebounceTimer = null;
14298
- }
14299
- }
14300
- /**
14301
- * Debounced sync triggered by a storage:remote-updated event.
14302
- * Waits 500ms to batch rapid updates, then performs sync.
14303
- */
14304
- debouncedSyncFromRemoteUpdate(providerId, eventData) {
14305
- if (this.syncDebounceTimer) {
14306
- clearTimeout(this.syncDebounceTimer);
14307
- }
14308
- this.syncDebounceTimer = setTimeout(() => {
14309
- this.syncDebounceTimer = null;
14310
- this.sync().then((result) => {
14311
- const data = eventData;
14312
- this.deps?.emitEvent("sync:remote-update", {
14313
- providerId,
14314
- name: data?.name ?? "",
14315
- sequence: data?.sequence ?? 0,
14316
- cid: data?.cid ?? "",
14317
- added: result.added,
14318
- removed: result.removed
14319
- });
14320
- }).catch((err) => {
14321
- logger.debug("Payments", "Auto-sync from remote update failed:", err);
14322
- });
14323
- }, _PaymentsModule.SYNC_DEBOUNCE_MS);
14324
- }
14325
14175
  /**
14326
14176
  * Get all active (non-disabled) token storage providers
14327
14177
  */
@@ -14366,7 +14216,6 @@ var PaymentsModule = class _PaymentsModule {
14366
14216
  updateTokenStorageProviders(providers) {
14367
14217
  if (this.deps) {
14368
14218
  this.deps.tokenStorageProviders = providers;
14369
- this.subscribeToStorageEvents();
14370
14219
  }
14371
14220
  }
14372
14221
  /**
@@ -14528,6 +14377,10 @@ var PaymentsModule = class _PaymentsModule {
14528
14377
  teardownDeliveryPump() {
14529
14378
  this.deliveryWakeUnsub?.();
14530
14379
  this.deliveryWakeUnsub = null;
14380
+ if (this.inventoryDebounceTimer !== null) {
14381
+ clearTimeout(this.inventoryDebounceTimer);
14382
+ this.inventoryDebounceTimer = null;
14383
+ }
14531
14384
  if (this.deliveryPollTimer !== null) {
14532
14385
  clearInterval(this.deliveryPollTimer);
14533
14386
  this.deliveryPollTimer = null;
@@ -14567,11 +14420,11 @@ var PaymentsModule = class _PaymentsModule {
14567
14420
  * without waiting for the next poll tick.
14568
14421
  */
14569
14422
  debouncedInventorySyncFromWake() {
14570
- if (this.syncDebounceTimer) {
14571
- clearTimeout(this.syncDebounceTimer);
14423
+ if (this.inventoryDebounceTimer) {
14424
+ clearTimeout(this.inventoryDebounceTimer);
14572
14425
  }
14573
- this.syncDebounceTimer = setTimeout(() => {
14574
- this.syncDebounceTimer = null;
14426
+ this.inventoryDebounceTimer = setTimeout(() => {
14427
+ this.inventoryDebounceTimer = null;
14575
14428
  this.pumpHealth.run("inventory", () => this.resyncInventory(true));
14576
14429
  }, _PaymentsModule.SYNC_DEBOUNCE_MS);
14577
14430
  }
@@ -30710,16 +30563,6 @@ var Sphere = class _Sphere {
30710
30563
  });
30711
30564
  if (unsub) this._providerEventCleanups.push(unsub);
30712
30565
  }
30713
- for (const [providerId, provider] of this._tokenStorageProviders) {
30714
- if (typeof provider.onEvent === "function") {
30715
- const unsub = provider.onEvent((event) => {
30716
- if (event.type === "storage:error" || event.type === "sync:error") {
30717
- this.emitConnectionChanged(providerId, provider.isConnected(), provider.getStatus(), event.error);
30718
- }
30719
- });
30720
- if (unsub) this._providerEventCleanups.push(unsub);
30721
- }
30722
- }
30723
30566
  }
30724
30567
  /**
30725
30568
  * Emit connection:changed with deduplication — only emits if status actually changed.