@unicitylabs/sphere-sdk 0.1.4 → 0.1.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.
@@ -236,13 +236,17 @@ declare class FileStorageProvider implements StorageProvider {
236
236
  has(key: string): Promise<boolean>;
237
237
  keys(prefix?: string): Promise<string[]>;
238
238
  clear(prefix?: string): Promise<void>;
239
+ /**
240
+ * Get full storage key with address prefix for per-address keys
241
+ */
242
+ private getFullKey;
239
243
  private save;
240
244
  }
241
245
  declare function createFileStorageProvider(config: FileStorageProviderConfig | string): FileStorageProvider;
242
246
 
243
247
  /**
244
248
  * File Token Storage Provider for Node.js
245
- * Stores tokens as individual JSON files
249
+ * Stores tokens as individual JSON files in per-address subdirectories
246
250
  */
247
251
 
248
252
  interface FileTokenStorageConfig {
@@ -253,11 +257,16 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
253
257
  readonly id = "file-token-storage";
254
258
  readonly name = "File Token Storage";
255
259
  readonly type: "local";
256
- private tokensDir;
260
+ private baseTokensDir;
257
261
  private status;
258
262
  private identity;
259
263
  constructor(config: FileTokenStorageConfig | string);
260
264
  setIdentity(identity: FullIdentity): void;
265
+ /**
266
+ * Get tokens directory for current address
267
+ * Format: {baseTokensDir}/{addressId}/
268
+ */
269
+ private get tokensDir();
261
270
  initialize(): Promise<boolean>;
262
271
  shutdown(): Promise<void>;
263
272
  connect(): Promise<void>;
@@ -236,13 +236,17 @@ declare class FileStorageProvider implements StorageProvider {
236
236
  has(key: string): Promise<boolean>;
237
237
  keys(prefix?: string): Promise<string[]>;
238
238
  clear(prefix?: string): Promise<void>;
239
+ /**
240
+ * Get full storage key with address prefix for per-address keys
241
+ */
242
+ private getFullKey;
239
243
  private save;
240
244
  }
241
245
  declare function createFileStorageProvider(config: FileStorageProviderConfig | string): FileStorageProvider;
242
246
 
243
247
  /**
244
248
  * File Token Storage Provider for Node.js
245
- * Stores tokens as individual JSON files
249
+ * Stores tokens as individual JSON files in per-address subdirectories
246
250
  */
247
251
 
248
252
  interface FileTokenStorageConfig {
@@ -253,11 +257,16 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
253
257
  readonly id = "file-token-storage";
254
258
  readonly name = "File Token Storage";
255
259
  readonly type: "local";
256
- private tokensDir;
260
+ private baseTokensDir;
257
261
  private status;
258
262
  private identity;
259
263
  constructor(config: FileTokenStorageConfig | string);
260
264
  setIdentity(identity: FullIdentity): void;
265
+ /**
266
+ * Get tokens directory for current address
267
+ * Format: {baseTokensDir}/{addressId}/
268
+ */
269
+ private get tokensDir();
261
270
  initialize(): Promise<boolean>;
262
271
  shutdown(): Promise<void>;
263
272
  connect(): Promise<void>;
@@ -1,6 +1,131 @@
1
1
  // impl/nodejs/storage/FileStorageProvider.ts
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
+
5
+ // constants.ts
6
+ var STORAGE_KEYS_GLOBAL = {
7
+ /** Encrypted BIP39 mnemonic */
8
+ MNEMONIC: "mnemonic",
9
+ /** Encrypted master private key */
10
+ MASTER_KEY: "master_key",
11
+ /** BIP32 chain code */
12
+ CHAIN_CODE: "chain_code",
13
+ /** HD derivation path (full path like m/44'/0'/0'/0/0) */
14
+ DERIVATION_PATH: "derivation_path",
15
+ /** Base derivation path (like m/44'/0'/0' without chain/index) */
16
+ BASE_PATH: "base_path",
17
+ /** Derivation mode: bip32, wif_hmac, legacy_hmac */
18
+ DERIVATION_MODE: "derivation_mode",
19
+ /** Wallet source: mnemonic, file, unknown */
20
+ WALLET_SOURCE: "wallet_source",
21
+ /** Wallet existence flag */
22
+ WALLET_EXISTS: "wallet_exists",
23
+ /** Current active address index */
24
+ CURRENT_ADDRESS_INDEX: "current_address_index",
25
+ /** Index of address nametags (JSON: { "0": "alice", "1": "bob" }) - for discovery */
26
+ ADDRESS_NAMETAGS: "address_nametags"
27
+ };
28
+ var STORAGE_KEYS_ADDRESS = {
29
+ /** Pending transfers for this address */
30
+ PENDING_TRANSFERS: "pending_transfers",
31
+ /** Transfer outbox for this address */
32
+ OUTBOX: "outbox",
33
+ /** Conversations for this address */
34
+ CONVERSATIONS: "conversations",
35
+ /** Messages for this address */
36
+ MESSAGES: "messages",
37
+ /** Transaction history for this address */
38
+ TRANSACTION_HISTORY: "transaction_history"
39
+ };
40
+ var STORAGE_KEYS = {
41
+ ...STORAGE_KEYS_GLOBAL,
42
+ ...STORAGE_KEYS_ADDRESS
43
+ };
44
+ function getAddressId(directAddress) {
45
+ let hash = directAddress;
46
+ if (hash.startsWith("DIRECT://")) {
47
+ hash = hash.slice(9);
48
+ } else if (hash.startsWith("DIRECT:")) {
49
+ hash = hash.slice(7);
50
+ }
51
+ const first = hash.slice(0, 6).toLowerCase();
52
+ const last = hash.slice(-6).toLowerCase();
53
+ return `DIRECT_${first}_${last}`;
54
+ }
55
+ var DEFAULT_NOSTR_RELAYS = [
56
+ "wss://relay.unicity.network",
57
+ "wss://relay.damus.io",
58
+ "wss://nos.lol",
59
+ "wss://relay.nostr.band"
60
+ ];
61
+ var NOSTR_EVENT_KINDS = {
62
+ /** NIP-04 encrypted direct message */
63
+ DIRECT_MESSAGE: 4,
64
+ /** Token transfer (Unicity custom - 31113) */
65
+ TOKEN_TRANSFER: 31113,
66
+ /** Payment request (Unicity custom - 31115) */
67
+ PAYMENT_REQUEST: 31115,
68
+ /** Payment request response (Unicity custom - 31116) */
69
+ PAYMENT_REQUEST_RESPONSE: 31116,
70
+ /** Nametag binding (NIP-78 app-specific data) */
71
+ NAMETAG_BINDING: 30078,
72
+ /** Public broadcast */
73
+ BROADCAST: 1
74
+ };
75
+ var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
76
+ var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
77
+ var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
78
+ var DEFAULT_AGGREGATOR_TIMEOUT = 3e4;
79
+ var DEFAULT_AGGREGATOR_API_KEY = "sk_06365a9c44654841a366068bcfc68986";
80
+ var DEFAULT_IPFS_GATEWAYS = [
81
+ "https://ipfs.unicity.network",
82
+ "https://dweb.link",
83
+ "https://ipfs.io"
84
+ ];
85
+ var DEFAULT_BASE_PATH = "m/44'/0'/0'";
86
+ var DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
87
+ var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
88
+ var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
89
+ var TEST_NOSTR_RELAYS = [
90
+ "wss://nostr-relay.testnet.unicity.network"
91
+ ];
92
+ var NETWORKS = {
93
+ mainnet: {
94
+ name: "Mainnet",
95
+ aggregatorUrl: DEFAULT_AGGREGATOR_URL,
96
+ nostrRelays: DEFAULT_NOSTR_RELAYS,
97
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
98
+ electrumUrl: DEFAULT_ELECTRUM_URL
99
+ },
100
+ testnet: {
101
+ name: "Testnet",
102
+ aggregatorUrl: TEST_AGGREGATOR_URL,
103
+ nostrRelays: TEST_NOSTR_RELAYS,
104
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
105
+ electrumUrl: TEST_ELECTRUM_URL
106
+ },
107
+ dev: {
108
+ name: "Development",
109
+ aggregatorUrl: DEV_AGGREGATOR_URL,
110
+ nostrRelays: TEST_NOSTR_RELAYS,
111
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
112
+ electrumUrl: TEST_ELECTRUM_URL
113
+ }
114
+ };
115
+ var TIMEOUTS = {
116
+ /** WebSocket connection timeout */
117
+ WEBSOCKET_CONNECT: 1e4,
118
+ /** Nostr relay reconnect delay */
119
+ NOSTR_RECONNECT_DELAY: 3e3,
120
+ /** Max reconnect attempts */
121
+ MAX_RECONNECT_ATTEMPTS: 5,
122
+ /** Proof polling interval */
123
+ PROOF_POLL_INTERVAL: 1e3,
124
+ /** Sync interval */
125
+ SYNC_INTERVAL: 6e4
126
+ };
127
+
128
+ // impl/nodejs/storage/FileStorageProvider.ts
4
129
  var FileStorageProvider = class {
5
130
  id = "file-storage";
6
131
  name = "File Storage";
@@ -53,18 +178,22 @@ var FileStorageProvider = class {
53
178
  return this.status;
54
179
  }
55
180
  async get(key) {
56
- return this.data[key] ?? null;
181
+ const fullKey = this.getFullKey(key);
182
+ return this.data[fullKey] ?? null;
57
183
  }
58
184
  async set(key, value) {
59
- this.data[key] = value;
185
+ const fullKey = this.getFullKey(key);
186
+ this.data[fullKey] = value;
60
187
  await this.save();
61
188
  }
62
189
  async remove(key) {
63
- delete this.data[key];
190
+ const fullKey = this.getFullKey(key);
191
+ delete this.data[fullKey];
64
192
  await this.save();
65
193
  }
66
194
  async has(key) {
67
- return key in this.data;
195
+ const fullKey = this.getFullKey(key);
196
+ return fullKey in this.data;
68
197
  }
69
198
  async keys(prefix) {
70
199
  const allKeys = Object.keys(this.data);
@@ -84,6 +213,19 @@ var FileStorageProvider = class {
84
213
  }
85
214
  await this.save();
86
215
  }
216
+ /**
217
+ * Get full storage key with address prefix for per-address keys
218
+ */
219
+ getFullKey(key) {
220
+ const isPerAddressKey = Object.values(STORAGE_KEYS_ADDRESS).includes(
221
+ key
222
+ );
223
+ if (isPerAddressKey && this._identity?.directAddress) {
224
+ const addressId = getAddressId(this._identity.directAddress);
225
+ return `${addressId}_${key}`;
226
+ }
227
+ return key;
228
+ }
87
229
  async save() {
88
230
  if (!fs.existsSync(this.dataDir)) {
89
231
  fs.mkdirSync(this.dataDir, { recursive: true });
@@ -102,15 +244,26 @@ var FileTokenStorageProvider = class {
102
244
  id = "file-token-storage";
103
245
  name = "File Token Storage";
104
246
  type = "local";
105
- tokensDir;
247
+ baseTokensDir;
106
248
  status = "disconnected";
107
249
  identity = null;
108
250
  constructor(config) {
109
- this.tokensDir = typeof config === "string" ? config : config.tokensDir;
251
+ this.baseTokensDir = typeof config === "string" ? config : config.tokensDir;
110
252
  }
111
253
  setIdentity(identity) {
112
254
  this.identity = identity;
113
255
  }
256
+ /**
257
+ * Get tokens directory for current address
258
+ * Format: {baseTokensDir}/{addressId}/
259
+ */
260
+ get tokensDir() {
261
+ if (this.identity?.directAddress) {
262
+ const addressId = getAddressId(this.identity.directAddress);
263
+ return path2.join(this.baseTokensDir, addressId);
264
+ }
265
+ return this.baseTokensDir;
266
+ }
114
267
  async initialize() {
115
268
  if (!fs2.existsSync(this.tokensDir)) {
116
269
  fs2.mkdirSync(this.tokensDir, { recursive: true });
@@ -822,122 +975,6 @@ function defaultUUIDGenerator() {
822
975
  });
823
976
  }
824
977
 
825
- // constants.ts
826
- var STORAGE_PREFIX = "sphere_";
827
- var STORAGE_KEYS = {
828
- /** Encrypted BIP39 mnemonic */
829
- MNEMONIC: `${STORAGE_PREFIX}mnemonic`,
830
- /** Encrypted master private key */
831
- MASTER_KEY: `${STORAGE_PREFIX}master_key`,
832
- /** BIP32 chain code */
833
- CHAIN_CODE: `${STORAGE_PREFIX}chain_code`,
834
- /** HD derivation path (full path like m/44'/0'/0'/0/0) */
835
- DERIVATION_PATH: `${STORAGE_PREFIX}derivation_path`,
836
- /** Base derivation path (like m/44'/0'/0' without chain/index) */
837
- BASE_PATH: `${STORAGE_PREFIX}base_path`,
838
- /** Derivation mode: bip32, wif_hmac, legacy_hmac */
839
- DERIVATION_MODE: `${STORAGE_PREFIX}derivation_mode`,
840
- /** Wallet source: mnemonic, file, unknown */
841
- WALLET_SOURCE: `${STORAGE_PREFIX}wallet_source`,
842
- /** Wallet existence flag */
843
- WALLET_EXISTS: `${STORAGE_PREFIX}wallet_exists`,
844
- /** Registered nametag (legacy - single address) */
845
- NAMETAG: `${STORAGE_PREFIX}nametag`,
846
- /** Current active address index */
847
- CURRENT_ADDRESS_INDEX: `${STORAGE_PREFIX}current_address_index`,
848
- /** Address nametags map (JSON: { "0": "alice", "1": "bob" }) */
849
- ADDRESS_NAMETAGS: `${STORAGE_PREFIX}address_nametags`,
850
- /** Token data */
851
- TOKENS: `${STORAGE_PREFIX}tokens`,
852
- /** Pending transfers */
853
- PENDING_TRANSFERS: `${STORAGE_PREFIX}pending_transfers`,
854
- /** Transfer outbox */
855
- OUTBOX: `${STORAGE_PREFIX}outbox`,
856
- /** Conversations */
857
- CONVERSATIONS: `${STORAGE_PREFIX}conversations`,
858
- /** Messages */
859
- MESSAGES: `${STORAGE_PREFIX}messages`,
860
- /** Transaction history */
861
- TRANSACTION_HISTORY: `${STORAGE_PREFIX}transaction_history`,
862
- /** Archived tokens (spent token history) */
863
- ARCHIVED_TOKENS: `${STORAGE_PREFIX}archived_tokens`,
864
- /** Tombstones (records of deleted/spent tokens) */
865
- TOMBSTONES: `${STORAGE_PREFIX}tombstones`,
866
- /** Forked tokens (alternative histories) */
867
- FORKED_TOKENS: `${STORAGE_PREFIX}forked_tokens`
868
- };
869
- var DEFAULT_NOSTR_RELAYS = [
870
- "wss://relay.unicity.network",
871
- "wss://relay.damus.io",
872
- "wss://nos.lol",
873
- "wss://relay.nostr.band"
874
- ];
875
- var NOSTR_EVENT_KINDS = {
876
- /** NIP-04 encrypted direct message */
877
- DIRECT_MESSAGE: 4,
878
- /** Token transfer (Unicity custom - 31113) */
879
- TOKEN_TRANSFER: 31113,
880
- /** Payment request (Unicity custom - 31115) */
881
- PAYMENT_REQUEST: 31115,
882
- /** Payment request response (Unicity custom - 31116) */
883
- PAYMENT_REQUEST_RESPONSE: 31116,
884
- /** Nametag binding (NIP-78 app-specific data) */
885
- NAMETAG_BINDING: 30078,
886
- /** Public broadcast */
887
- BROADCAST: 1
888
- };
889
- var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
890
- var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
891
- var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
892
- var DEFAULT_AGGREGATOR_TIMEOUT = 3e4;
893
- var DEFAULT_IPFS_GATEWAYS = [
894
- "https://ipfs.unicity.network",
895
- "https://dweb.link",
896
- "https://ipfs.io"
897
- ];
898
- var DEFAULT_BASE_PATH = "m/44'/0'/0'";
899
- var DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
900
- var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
901
- var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
902
- var TEST_NOSTR_RELAYS = [
903
- "wss://nostr-relay.testnet.unicity.network"
904
- ];
905
- var NETWORKS = {
906
- mainnet: {
907
- name: "Mainnet",
908
- aggregatorUrl: DEFAULT_AGGREGATOR_URL,
909
- nostrRelays: DEFAULT_NOSTR_RELAYS,
910
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
911
- electrumUrl: DEFAULT_ELECTRUM_URL
912
- },
913
- testnet: {
914
- name: "Testnet",
915
- aggregatorUrl: TEST_AGGREGATOR_URL,
916
- nostrRelays: TEST_NOSTR_RELAYS,
917
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
918
- electrumUrl: TEST_ELECTRUM_URL
919
- },
920
- dev: {
921
- name: "Development",
922
- aggregatorUrl: DEV_AGGREGATOR_URL,
923
- nostrRelays: TEST_NOSTR_RELAYS,
924
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
925
- electrumUrl: TEST_ELECTRUM_URL
926
- }
927
- };
928
- var TIMEOUTS = {
929
- /** WebSocket connection timeout */
930
- WEBSOCKET_CONNECT: 1e4,
931
- /** Nostr relay reconnect delay */
932
- NOSTR_RECONNECT_DELAY: 3e3,
933
- /** Max reconnect attempts */
934
- MAX_RECONNECT_ATTEMPTS: 5,
935
- /** Proof polling interval */
936
- PROOF_POLL_INTERVAL: 1e3,
937
- /** Sync interval */
938
- SYNC_INTERVAL: 6e4
939
- };
940
-
941
978
  // transport/NostrTransportProvider.ts
942
979
  var EVENT_KINDS = NOSTR_EVENT_KINDS;
943
980
  function deriveNametagEncryptionKey(privateKeyHex) {
@@ -2510,7 +2547,7 @@ function resolveOracleConfig(network, config) {
2510
2547
  const networkConfig = getNetworkConfig(network);
2511
2548
  return {
2512
2549
  url: config?.url ?? networkConfig.aggregatorUrl,
2513
- apiKey: config?.apiKey,
2550
+ apiKey: config?.apiKey ?? DEFAULT_AGGREGATOR_API_KEY,
2514
2551
  timeout: config?.timeout,
2515
2552
  skipVerification: config?.skipVerification,
2516
2553
  debug: config?.debug,