@unicitylabs/sphere-sdk 0.4.8 → 0.5.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/index.d.cts CHANGED
@@ -628,6 +628,8 @@ interface InstantSplitProcessResult {
628
628
  * Options for instant split send operation
629
629
  */
630
630
  interface InstantSplitOptions {
631
+ /** Optional memo/message to include with the transfer */
632
+ memo?: string;
631
633
  /** Timeout for Nostr delivery in ms (default: 30000) */
632
634
  nostrTimeoutMs?: number;
633
635
  /** Timeout for burn proof wait in ms (default: 60000) */
@@ -1167,7 +1169,7 @@ interface TrackedAddress extends TrackedAddressEntry {
1167
1169
  /** Primary nametag (from nametag cache, without @ prefix) */
1168
1170
  readonly nametag?: string;
1169
1171
  }
1170
- type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'payment_request:incoming' | 'payment_request:accepted' | 'payment_request:rejected' | 'payment_request:paid' | 'payment_request:response' | 'message:dm' | 'message:read' | 'message:typing' | 'composing:started' | 'message:broadcast' | 'sync:started' | 'sync:completed' | 'sync:provider' | 'sync:error' | 'connection:changed' | 'nametag:registered' | 'nametag:recovered' | 'identity:changed' | 'address:activated' | 'address:hidden' | 'address:unhidden' | 'sync:remote-update' | 'groupchat:message' | 'groupchat:joined' | 'groupchat:left' | 'groupchat:kicked' | 'groupchat:group_deleted' | 'groupchat:updated' | 'groupchat:connection';
1172
+ type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'payment_request:incoming' | 'payment_request:accepted' | 'payment_request:rejected' | 'payment_request:paid' | 'payment_request:response' | 'message:dm' | 'message:read' | 'message:typing' | 'composing:started' | 'message:broadcast' | 'sync:started' | 'sync:completed' | 'sync:provider' | 'sync:error' | 'connection:changed' | 'nametag:registered' | 'nametag:recovered' | 'identity:changed' | 'address:activated' | 'address:hidden' | 'address:unhidden' | 'sync:remote-update' | 'groupchat:message' | 'groupchat:joined' | 'groupchat:left' | 'groupchat:kicked' | 'groupchat:group_deleted' | 'groupchat:updated' | 'groupchat:connection' | 'history:updated';
1171
1173
  interface SphereEventMap {
1172
1174
  'transfer:incoming': IncomingTransfer;
1173
1175
  'transfer:confirmed': TransferResult;
@@ -1267,6 +1269,7 @@ interface SphereEventMap {
1267
1269
  'groupchat:connection': {
1268
1270
  connected: boolean;
1269
1271
  };
1272
+ 'history:updated': TransactionHistoryEntry;
1270
1273
  }
1271
1274
  type SphereEventHandler<T extends SphereEventType> = (data: SphereEventMap[T]) => void;
1272
1275
  interface SphereConfig {
@@ -1437,6 +1440,199 @@ interface SphereStatus {
1437
1440
  price: ProviderStatusInfo[];
1438
1441
  }
1439
1442
 
1443
+ /**
1444
+ * Storage Provider Interface
1445
+ * Platform-independent storage abstraction
1446
+ */
1447
+
1448
+ /**
1449
+ * Basic key-value storage provider
1450
+ * All operations are async for platform flexibility
1451
+ */
1452
+ interface StorageProvider extends BaseProvider {
1453
+ /**
1454
+ * Set identity for scoped storage
1455
+ */
1456
+ setIdentity(identity: FullIdentity): void;
1457
+ /**
1458
+ * Get value by key
1459
+ */
1460
+ get(key: string): Promise<string | null>;
1461
+ /**
1462
+ * Set value by key
1463
+ */
1464
+ set(key: string, value: string): Promise<void>;
1465
+ /**
1466
+ * Remove key
1467
+ */
1468
+ remove(key: string): Promise<void>;
1469
+ /**
1470
+ * Check if key exists
1471
+ */
1472
+ has(key: string): Promise<boolean>;
1473
+ /**
1474
+ * Get all keys with optional prefix filter
1475
+ */
1476
+ keys(prefix?: string): Promise<string[]>;
1477
+ /**
1478
+ * Clear all keys with optional prefix filter
1479
+ */
1480
+ clear(prefix?: string): Promise<void>;
1481
+ /**
1482
+ * Save tracked addresses (only user state: index, hidden, timestamps)
1483
+ */
1484
+ saveTrackedAddresses(entries: TrackedAddressEntry[]): Promise<void>;
1485
+ /**
1486
+ * Load tracked addresses
1487
+ */
1488
+ loadTrackedAddresses(): Promise<TrackedAddressEntry[]>;
1489
+ }
1490
+ interface HistoryRecord {
1491
+ /** Composite dedup key (primary key) — e.g. "RECEIVED_v5split_abc123" */
1492
+ dedupKey: string;
1493
+ /** UUID for public API consumption */
1494
+ id: string;
1495
+ type: 'SENT' | 'RECEIVED' | 'SPLIT' | 'MINT';
1496
+ amount: string;
1497
+ coinId: string;
1498
+ symbol: string;
1499
+ timestamp: number;
1500
+ transferId?: string;
1501
+ /** Genesis tokenId this entry relates to (used for dedup) */
1502
+ tokenId?: string;
1503
+ senderPubkey?: string;
1504
+ senderAddress?: string;
1505
+ senderNametag?: string;
1506
+ recipientPubkey?: string;
1507
+ recipientAddress?: string;
1508
+ recipientNametag?: string;
1509
+ /** Optional memo/message attached to the transfer */
1510
+ memo?: string;
1511
+ }
1512
+ /**
1513
+ * Storage result types
1514
+ */
1515
+ interface SaveResult {
1516
+ success: boolean;
1517
+ cid?: string;
1518
+ error?: string;
1519
+ timestamp: number;
1520
+ }
1521
+ interface LoadResult<T = unknown> {
1522
+ success: boolean;
1523
+ data?: T;
1524
+ error?: string;
1525
+ source: 'local' | 'remote' | 'cache';
1526
+ timestamp: number;
1527
+ }
1528
+ interface SyncResult<T = unknown> {
1529
+ success: boolean;
1530
+ merged?: T;
1531
+ added: number;
1532
+ removed: number;
1533
+ conflicts: number;
1534
+ error?: string;
1535
+ }
1536
+ /**
1537
+ * Token-specific storage provider
1538
+ * Handles token persistence with sync capabilities
1539
+ */
1540
+ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
1541
+ /**
1542
+ * Set identity for storage scope
1543
+ */
1544
+ setIdentity(identity: FullIdentity): void;
1545
+ /**
1546
+ * Initialize provider (called once after identity is set)
1547
+ */
1548
+ initialize(): Promise<boolean>;
1549
+ /**
1550
+ * Shutdown provider
1551
+ */
1552
+ shutdown(): Promise<void>;
1553
+ /**
1554
+ * Save token data
1555
+ */
1556
+ save(data: TData): Promise<SaveResult>;
1557
+ /**
1558
+ * Load token data
1559
+ */
1560
+ load(identifier?: string): Promise<LoadResult<TData>>;
1561
+ /**
1562
+ * Sync local data with remote
1563
+ */
1564
+ sync(localData: TData): Promise<SyncResult<TData>>;
1565
+ /**
1566
+ * Check if data exists
1567
+ */
1568
+ exists?(identifier?: string): Promise<boolean>;
1569
+ /**
1570
+ * Clear all data
1571
+ */
1572
+ clear?(): Promise<boolean>;
1573
+ /**
1574
+ * Subscribe to storage events
1575
+ */
1576
+ onEvent?(callback: StorageEventCallback): () => void;
1577
+ /** Store a history entry (upsert by dedupKey) */
1578
+ addHistoryEntry?(entry: HistoryRecord): Promise<void>;
1579
+ /** Get all history entries sorted by timestamp descending */
1580
+ getHistoryEntries?(): Promise<HistoryRecord[]>;
1581
+ /** Check if a history entry exists by dedupKey */
1582
+ hasHistoryEntry?(dedupKey: string): Promise<boolean>;
1583
+ /** Clear all history entries */
1584
+ clearHistory?(): Promise<void>;
1585
+ /** Bulk import history entries (skip existing dedupKeys). Returns count of newly imported. */
1586
+ importHistoryEntries?(entries: HistoryRecord[]): Promise<number>;
1587
+ }
1588
+ type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
1589
+ interface StorageEvent {
1590
+ type: StorageEventType;
1591
+ timestamp: number;
1592
+ data?: unknown;
1593
+ error?: string;
1594
+ }
1595
+ type StorageEventCallback = (event: StorageEvent) => void;
1596
+ interface TxfStorageDataBase {
1597
+ _meta: TxfMeta;
1598
+ _tombstones?: TxfTombstone[];
1599
+ _outbox?: TxfOutboxEntry[];
1600
+ _sent?: TxfSentEntry[];
1601
+ _invalid?: TxfInvalidEntry[];
1602
+ [key: `_${string}`]: unknown;
1603
+ }
1604
+ interface TxfMeta {
1605
+ version: number;
1606
+ address: string;
1607
+ ipnsName?: string;
1608
+ formatVersion: string;
1609
+ updatedAt: number;
1610
+ }
1611
+ interface TxfTombstone {
1612
+ tokenId: string;
1613
+ stateHash: string;
1614
+ timestamp: number;
1615
+ }
1616
+ interface TxfOutboxEntry {
1617
+ id: string;
1618
+ status: string;
1619
+ tokenId: string;
1620
+ recipient: string;
1621
+ createdAt: number;
1622
+ data: unknown;
1623
+ }
1624
+ interface TxfSentEntry {
1625
+ tokenId: string;
1626
+ recipient: string;
1627
+ txHash: string;
1628
+ sentAt: number;
1629
+ }
1630
+ interface TxfInvalidEntry {
1631
+ tokenId: string;
1632
+ reason: string;
1633
+ detectedAt: number;
1634
+ }
1635
+
1440
1636
  /**
1441
1637
  * Transport Provider Interface
1442
1638
  * Platform-independent P2P messaging abstraction
@@ -1988,167 +2184,6 @@ interface MintNametagResult {
1988
2184
  error?: string;
1989
2185
  }
1990
2186
 
1991
- /**
1992
- * Storage Provider Interface
1993
- * Platform-independent storage abstraction
1994
- */
1995
-
1996
- /**
1997
- * Basic key-value storage provider
1998
- * All operations are async for platform flexibility
1999
- */
2000
- interface StorageProvider extends BaseProvider {
2001
- /**
2002
- * Set identity for scoped storage
2003
- */
2004
- setIdentity(identity: FullIdentity): void;
2005
- /**
2006
- * Get value by key
2007
- */
2008
- get(key: string): Promise<string | null>;
2009
- /**
2010
- * Set value by key
2011
- */
2012
- set(key: string, value: string): Promise<void>;
2013
- /**
2014
- * Remove key
2015
- */
2016
- remove(key: string): Promise<void>;
2017
- /**
2018
- * Check if key exists
2019
- */
2020
- has(key: string): Promise<boolean>;
2021
- /**
2022
- * Get all keys with optional prefix filter
2023
- */
2024
- keys(prefix?: string): Promise<string[]>;
2025
- /**
2026
- * Clear all keys with optional prefix filter
2027
- */
2028
- clear(prefix?: string): Promise<void>;
2029
- /**
2030
- * Save tracked addresses (only user state: index, hidden, timestamps)
2031
- */
2032
- saveTrackedAddresses(entries: TrackedAddressEntry[]): Promise<void>;
2033
- /**
2034
- * Load tracked addresses
2035
- */
2036
- loadTrackedAddresses(): Promise<TrackedAddressEntry[]>;
2037
- }
2038
- /**
2039
- * Storage result types
2040
- */
2041
- interface SaveResult {
2042
- success: boolean;
2043
- cid?: string;
2044
- error?: string;
2045
- timestamp: number;
2046
- }
2047
- interface LoadResult<T = unknown> {
2048
- success: boolean;
2049
- data?: T;
2050
- error?: string;
2051
- source: 'local' | 'remote' | 'cache';
2052
- timestamp: number;
2053
- }
2054
- interface SyncResult<T = unknown> {
2055
- success: boolean;
2056
- merged?: T;
2057
- added: number;
2058
- removed: number;
2059
- conflicts: number;
2060
- error?: string;
2061
- }
2062
- /**
2063
- * Token-specific storage provider
2064
- * Handles token persistence with sync capabilities
2065
- */
2066
- interface TokenStorageProvider<TData = unknown> extends BaseProvider {
2067
- /**
2068
- * Set identity for storage scope
2069
- */
2070
- setIdentity(identity: FullIdentity): void;
2071
- /**
2072
- * Initialize provider (called once after identity is set)
2073
- */
2074
- initialize(): Promise<boolean>;
2075
- /**
2076
- * Shutdown provider
2077
- */
2078
- shutdown(): Promise<void>;
2079
- /**
2080
- * Save token data
2081
- */
2082
- save(data: TData): Promise<SaveResult>;
2083
- /**
2084
- * Load token data
2085
- */
2086
- load(identifier?: string): Promise<LoadResult<TData>>;
2087
- /**
2088
- * Sync local data with remote
2089
- */
2090
- sync(localData: TData): Promise<SyncResult<TData>>;
2091
- /**
2092
- * Check if data exists
2093
- */
2094
- exists?(identifier?: string): Promise<boolean>;
2095
- /**
2096
- * Clear all data
2097
- */
2098
- clear?(): Promise<boolean>;
2099
- /**
2100
- * Subscribe to storage events
2101
- */
2102
- onEvent?(callback: StorageEventCallback): () => void;
2103
- }
2104
- type StorageEventType = 'storage:saving' | 'storage:saved' | 'storage:loading' | 'storage:loaded' | 'storage:error' | 'storage:remote-updated' | 'sync:started' | 'sync:completed' | 'sync:conflict' | 'sync:error';
2105
- interface StorageEvent {
2106
- type: StorageEventType;
2107
- timestamp: number;
2108
- data?: unknown;
2109
- error?: string;
2110
- }
2111
- type StorageEventCallback = (event: StorageEvent) => void;
2112
- interface TxfStorageDataBase {
2113
- _meta: TxfMeta;
2114
- _tombstones?: TxfTombstone[];
2115
- _outbox?: TxfOutboxEntry[];
2116
- _sent?: TxfSentEntry[];
2117
- _invalid?: TxfInvalidEntry[];
2118
- [key: `_${string}`]: unknown;
2119
- }
2120
- interface TxfMeta {
2121
- version: number;
2122
- address: string;
2123
- ipnsName?: string;
2124
- formatVersion: string;
2125
- updatedAt: number;
2126
- }
2127
- interface TxfTombstone {
2128
- tokenId: string;
2129
- stateHash: string;
2130
- timestamp: number;
2131
- }
2132
- interface TxfOutboxEntry {
2133
- id: string;
2134
- status: string;
2135
- tokenId: string;
2136
- recipient: string;
2137
- createdAt: number;
2138
- data: unknown;
2139
- }
2140
- interface TxfSentEntry {
2141
- tokenId: string;
2142
- recipient: string;
2143
- txHash: string;
2144
- sentAt: number;
2145
- }
2146
- interface TxfInvalidEntry {
2147
- tokenId: string;
2148
- reason: string;
2149
- detectedAt: number;
2150
- }
2151
-
2152
2187
  /**
2153
2188
  * Oracle Provider Interface
2154
2189
  * Platform-independent Unicity oracle abstraction
@@ -2453,30 +2488,10 @@ declare class CoinGeckoPriceProvider implements PriceProvider {
2453
2488
  declare function createPriceProvider(config: PriceProviderConfig): PriceProvider;
2454
2489
 
2455
2490
  /**
2456
- * Payments Module
2457
- * Platform-independent token operations with full wallet repository functionality
2458
- *
2459
- * Includes:
2460
- * - Token CRUD operations
2461
- * - Tombstones for sync
2462
- * - Archived tokens (spent history)
2463
- * - Forked tokens (alternative histories)
2464
- * - Transaction history
2465
- * - Nametag storage
2491
+ * Public history entry type — re-exported from the shared storage layer.
2492
+ * Single source of truth: {@link HistoryRecord} in `storage/storage-provider.ts`.
2466
2493
  */
2467
-
2468
- interface TransactionHistoryEntry {
2469
- id: string;
2470
- type: 'SENT' | 'RECEIVED' | 'SPLIT' | 'MINT';
2471
- amount: string;
2472
- coinId: string;
2473
- symbol: string;
2474
- timestamp: number;
2475
- recipientNametag?: string;
2476
- senderPubkey?: string;
2477
- /** TransferResult.id that created this entry (links history to transfer operation) */
2478
- transferId?: string;
2479
- }
2494
+ type TransactionHistoryEntry = HistoryRecord;
2480
2495
  interface ReceiveOptions {
2481
2496
  /** Wait for all unconfirmed tokens to be finalized (default: false).
2482
2497
  * When false, calls resolveUnconfirmed() once to submit pending commitments.
@@ -2543,7 +2558,7 @@ declare class PaymentsModule {
2543
2558
  private tombstones;
2544
2559
  private archivedTokens;
2545
2560
  private forkedTokens;
2546
- private transactionHistory;
2561
+ private _historyCache;
2547
2562
  private nametags;
2548
2563
  private paymentRequests;
2549
2564
  private paymentRequestHandlers;
@@ -2898,10 +2913,9 @@ declare class PaymentsModule {
2898
2913
  * the old state is archived and replaced with the incoming one.
2899
2914
  *
2900
2915
  * @param token - The token to add.
2901
- * @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
2902
2916
  * @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
2903
2917
  */
2904
- addToken(token: Token, skipHistory?: boolean): Promise<boolean>;
2918
+ addToken(token: Token): Promise<boolean>;
2905
2919
  /**
2906
2920
  * Update an existing token or add it if not found.
2907
2921
  *
@@ -2919,10 +2933,8 @@ declare class PaymentsModule {
2919
2933
  * entry is created unless `skipHistory` is `true`.
2920
2934
  *
2921
2935
  * @param tokenId - Local UUID of the token to remove.
2922
- * @param recipientNametag - Optional nametag of the transfer recipient (for history).
2923
- * @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
2924
2936
  */
2925
- removeToken(tokenId: string, recipientNametag?: string, skipHistory?: boolean): Promise<void>;
2937
+ removeToken(tokenId: string): Promise<void>;
2926
2938
  /**
2927
2939
  * Get all tombstone entries.
2928
2940
  *
@@ -3033,14 +3045,30 @@ declare class PaymentsModule {
3033
3045
  * @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
3034
3046
  */
3035
3047
  getHistory(): TransactionHistoryEntry[];
3048
+ /**
3049
+ * Best-effort resolve sender's DIRECT address and nametag from their transport pubkey.
3050
+ * Returns empty object if transport doesn't support resolution or lookup fails.
3051
+ */
3052
+ private resolveSenderInfo;
3036
3053
  /**
3037
3054
  * Append an entry to the transaction history.
3038
3055
  *
3039
- * A unique `id` is auto-generated. The entry is immediately persisted to storage.
3056
+ * A unique `id` and `dedupKey` are auto-generated. The entry is persisted to
3057
+ * the local token storage provider's `history` store (IndexedDB / file).
3058
+ * Duplicate entries with the same `dedupKey` are silently ignored (upsert).
3040
3059
  *
3041
- * @param entry - History entry fields (without `id`).
3060
+ * @param entry - History entry fields (without `id` and `dedupKey`).
3061
+ */
3062
+ addToHistory(entry: Omit<TransactionHistoryEntry, 'id' | 'dedupKey'>): Promise<void>;
3063
+ /**
3064
+ * Load history from the local token storage provider into the in-memory cache.
3065
+ * Also performs one-time migration from legacy KV storage.
3066
+ */
3067
+ loadHistory(): Promise<void>;
3068
+ /**
3069
+ * Get the first local token storage provider (for history operations).
3042
3070
  */
3043
- addToHistory(entry: Omit<TransactionHistoryEntry, 'id'>): Promise<void>;
3071
+ private getLocalTokenStorageProvider;
3044
3072
  /**
3045
3073
  * Set the nametag data for the current identity.
3046
3074
  *