sphere-connect 1.0.1

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.js ADDED
@@ -0,0 +1,1407 @@
1
+ 'use strict';
2
+
3
+ var tsSdk = require('@cedra-labs/ts-sdk');
4
+ var jose = require('jose');
5
+ var CryptoJS2 = require('crypto-js');
6
+ var react = require('react');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var CryptoJS2__default = /*#__PURE__*/_interopDefault(CryptoJS2);
12
+
13
+ // src/core/EventEmitter.ts
14
+ var EventEmitter = class {
15
+ constructor() {
16
+ this.listeners = /* @__PURE__ */ new Map();
17
+ }
18
+ on(event, listener) {
19
+ if (!this.listeners.has(event)) {
20
+ this.listeners.set(event, []);
21
+ }
22
+ this.listeners.get(event).push(listener);
23
+ return this;
24
+ }
25
+ off(event, listener) {
26
+ const eventListeners = this.listeners.get(event);
27
+ if (eventListeners) {
28
+ const index = eventListeners.indexOf(listener);
29
+ if (index !== -1) {
30
+ eventListeners.splice(index, 1);
31
+ }
32
+ }
33
+ return this;
34
+ }
35
+ emit(event, ...args) {
36
+ const eventListeners = this.listeners.get(event);
37
+ if (eventListeners && eventListeners.length > 0) {
38
+ eventListeners.forEach((listener) => listener(...args));
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ removeAllListeners(event) {
44
+ if (event) {
45
+ this.listeners.delete(event);
46
+ } else {
47
+ this.listeners.clear();
48
+ }
49
+ return this;
50
+ }
51
+ };
52
+
53
+ // src/types/index.ts
54
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
55
+ ErrorCode2["AUTHENTICATION_FAILED"] = "AUTHENTICATION_FAILED";
56
+ ErrorCode2["WALLET_CREATION_FAILED"] = "WALLET_CREATION_FAILED";
57
+ ErrorCode2["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
58
+ ErrorCode2["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
59
+ ErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
60
+ ErrorCode2["INVALID_ADDRESS"] = "INVALID_ADDRESS";
61
+ ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
62
+ ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
63
+ ErrorCode2["KEY_DERIVATION_FAILED"] = "KEY_DERIVATION_FAILED";
64
+ ErrorCode2["TRANSACTION_ABORTED"] = "TRANSACTION_ABORTED";
65
+ ErrorCode2["DISCARDED_TRANSACTION"] = "DISCARDED_TRANSACTION";
66
+ ErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
67
+ return ErrorCode2;
68
+ })(ErrorCode || {});
69
+ var SphereSDKError = class extends Error {
70
+ constructor(code, message, details) {
71
+ super(message);
72
+ this.code = code;
73
+ this.details = details;
74
+ this.name = "SphereSDKError";
75
+ }
76
+ };
77
+
78
+ // src/wallet/SphereWallet.ts
79
+ var SphereWallet = class {
80
+ constructor(clientOrKey, privateKeyOrNetwork, networkOrEndpoint, rpcEndpoint, indexerUrl) {
81
+ this.keylessConfig = null;
82
+ this._indexerUrl = null;
83
+ try {
84
+ if (clientOrKey instanceof tsSdk.Cedra) {
85
+ this.client = clientOrKey;
86
+ this.privateKeyHex = privateKeyOrNetwork;
87
+ const net = networkOrEndpoint;
88
+ this.network = this.mapNetwork(net || "testnet");
89
+ this._indexerUrl = rpcEndpoint || null;
90
+ const formattedKey = tsSdk.PrivateKey.formatPrivateKey(this.privateKeyHex, tsSdk.PrivateKeyVariants.Ed25519);
91
+ const privateKey = new tsSdk.Ed25519PrivateKey(formattedKey);
92
+ this.account = tsSdk.Account.fromPrivateKey({ privateKey });
93
+ } else {
94
+ this.privateKeyHex = clientOrKey;
95
+ const net = privateKeyOrNetwork;
96
+ this.network = this.mapNetwork(net || "testnet");
97
+ const endpoint = rpcEndpoint || networkOrEndpoint;
98
+ const config = new tsSdk.CedraConfig({
99
+ network: this.network,
100
+ fullnode: endpoint
101
+ });
102
+ this.client = new tsSdk.Cedra(config);
103
+ this._indexerUrl = indexerUrl || null;
104
+ const formattedKey = tsSdk.PrivateKey.formatPrivateKey(this.privateKeyHex, tsSdk.PrivateKeyVariants.Ed25519);
105
+ const privateKey = new tsSdk.Ed25519PrivateKey(formattedKey);
106
+ this.account = tsSdk.Account.fromPrivateKey({ privateKey });
107
+ }
108
+ } catch (error) {
109
+ throw new SphereSDKError(
110
+ "WALLET_CREATION_FAILED" /* WALLET_CREATION_FAILED */,
111
+ "Failed to create wallet",
112
+ error
113
+ );
114
+ }
115
+ }
116
+ getAddress() {
117
+ return this.account.accountAddress.toString();
118
+ }
119
+ getPublicKey() {
120
+ return this.account.publicKey.toString();
121
+ }
122
+ getIndexerUrl() {
123
+ return this._indexerUrl;
124
+ }
125
+ async existsOnChain() {
126
+ try {
127
+ await this.client.getAccountInfo({
128
+ accountAddress: this.account.accountAddress
129
+ });
130
+ return true;
131
+ } catch (error) {
132
+ return false;
133
+ }
134
+ }
135
+ async getBalance(coinType) {
136
+ const defaultCoinType = "0x1::cedra_coin::CedraCoin";
137
+ const targetCoinType = coinType || defaultCoinType;
138
+ try {
139
+ if (targetCoinType.startsWith("0x") && !targetCoinType.includes("::")) {
140
+ const [balance] = await this.client.view({
141
+ payload: {
142
+ function: "0x1::primary_fungible_store::balance",
143
+ typeArguments: ["0x1::fungible_asset::Metadata"],
144
+ functionArguments: [this.getAddress(), targetCoinType]
145
+ }
146
+ });
147
+ const [decimals] = await this.client.view({
148
+ payload: {
149
+ function: "0x1::fungible_asset::decimals",
150
+ typeArguments: ["0x1::fungible_asset::Metadata"],
151
+ functionArguments: [targetCoinType]
152
+ }
153
+ });
154
+ const amountVal = balance?.toString() || "0";
155
+ const decimalsVal = decimals ? Number(decimals) : 8;
156
+ return {
157
+ coinType: targetCoinType,
158
+ amount: amountVal,
159
+ decimals: decimalsVal,
160
+ formatted: (Number(amountVal) / Math.pow(10, decimalsVal)).toFixed(Math.min(decimalsVal, 8))
161
+ };
162
+ }
163
+ const amount = await this.client.getAccountCoinAmount({
164
+ accountAddress: this.account.accountAddress,
165
+ coinType: targetCoinType
166
+ });
167
+ return {
168
+ coinType: targetCoinType,
169
+ amount: amount.toString(),
170
+ decimals: 8,
171
+ formatted: (Number(amount) / 1e8).toFixed(8)
172
+ };
173
+ } catch (error) {
174
+ return {
175
+ coinType: targetCoinType,
176
+ amount: "0",
177
+ decimals: 8,
178
+ formatted: "0.00000000"
179
+ };
180
+ }
181
+ }
182
+ async getAllBalances() {
183
+ return [await this.getBalance()];
184
+ }
185
+ async sendTransaction(options, simulate = true) {
186
+ try {
187
+ const { to, amount, coinType, maxGasAmount, gasUnitPrice } = options;
188
+ const transaction = await this.client.transaction.build.simple({
189
+ sender: this.account.accountAddress,
190
+ data: {
191
+ function: coinType?.startsWith("0x") && !coinType.includes("::") ? "0x1::primary_fungible_store::transfer" : "0x1::cedra_account::transfer",
192
+ typeArguments: coinType?.startsWith("0x") && !coinType.includes("::") ? ["0x1::fungible_asset::Metadata"] : [],
193
+ functionArguments: coinType?.startsWith("0x") && !coinType.includes("::") ? [coinType, to, amount] : [to, amount]
194
+ },
195
+ options: {
196
+ maxGasAmount: maxGasAmount || 2e4,
197
+ gasUnitPrice
198
+ }
199
+ });
200
+ if (simulate) {
201
+ const [sim] = await this.client.transaction.simulate.simple({
202
+ signerPublicKey: this.account.publicKey,
203
+ transaction
204
+ });
205
+ if (!sim.success) throw new Error(`Simulation failed: ${sim.vm_status}`);
206
+ }
207
+ const authenticator = await this.client.transaction.sign({
208
+ signer: this.account,
209
+ transaction
210
+ });
211
+ const pending = await this.client.transaction.submit.simple({
212
+ transaction,
213
+ senderAuthenticator: authenticator
214
+ });
215
+ return await this.waitForTransaction(pending.hash);
216
+ } catch (error) {
217
+ throw new SphereSDKError("TRANSACTION_FAILED" /* TRANSACTION_FAILED */, error.message, error);
218
+ }
219
+ }
220
+ async waitForTransaction(hash) {
221
+ const tx = await this.client.waitForTransaction({ transactionHash: hash });
222
+ return {
223
+ hash,
224
+ success: tx.success,
225
+ vmStatus: tx.vm_status,
226
+ gasUsed: tx.gas_used,
227
+ version: tx.version
228
+ };
229
+ }
230
+ async getGasPrice() {
231
+ const res = await this.client.getGasPriceEstimation();
232
+ return res.gas_estimate;
233
+ }
234
+ async getTransactionHistory() {
235
+ const txs = await this.client.getAccountTransactions({
236
+ accountAddress: this.account.accountAddress
237
+ });
238
+ return txs.map((tx) => ({
239
+ hash: tx.hash,
240
+ success: tx.success,
241
+ type: tx.type,
242
+ sender: tx.sender,
243
+ receiver: tx.payload?.functionArguments?.[0],
244
+ amount: tx.payload?.functionArguments?.[1],
245
+ timestamp: parseInt(tx.timestamp || "0") / 1e3,
246
+ version: tx.version
247
+ }));
248
+ }
249
+ async simulateTransaction(options) {
250
+ const { to, amount, maxGasAmount, gasUnitPrice } = options;
251
+ const transaction = await this.client.transaction.build.simple({
252
+ sender: this.account.accountAddress,
253
+ data: {
254
+ function: "0x1::cedra_account::transfer",
255
+ functionArguments: [to, amount]
256
+ },
257
+ options: {
258
+ maxGasAmount: maxGasAmount || 2e4,
259
+ gasUnitPrice
260
+ }
261
+ });
262
+ const [res] = await this.client.transaction.simulate.simple({
263
+ signerPublicKey: this.account.publicKey,
264
+ transaction
265
+ });
266
+ return {
267
+ success: res.success,
268
+ gasUsed: res.gas_used,
269
+ gasUnitPrice: res.gas_unit_price,
270
+ totalGasCost: Number(res.gas_used) * Number(res.gas_unit_price),
271
+ vmStatus: res.vm_status
272
+ };
273
+ }
274
+ async signMessage(message) {
275
+ const sig = this.account.sign(new TextEncoder().encode(message));
276
+ return sig.toString();
277
+ }
278
+ async getAccountInfo() {
279
+ const info = await this.client.getAccountInfo({ accountAddress: this.account.accountAddress });
280
+ return {
281
+ address: this.getAddress(),
282
+ publicKey: this.getPublicKey(),
283
+ existsOnChain: true,
284
+ sequenceNumber: info.sequence_number,
285
+ authKey: info.authentication_key
286
+ };
287
+ }
288
+ async disconnect() {
289
+ this.account = null;
290
+ }
291
+ updateNetwork(network, rpcEndpoint) {
292
+ this.network = this.mapNetwork(network);
293
+ this.client = new tsSdk.Cedra(new tsSdk.CedraConfig({ network: this.network, fullnode: rpcEndpoint }));
294
+ }
295
+ mapNetwork(network) {
296
+ switch (network.toLowerCase()) {
297
+ case "mainnet":
298
+ return tsSdk.Network.MAINNET;
299
+ case "testnet":
300
+ return tsSdk.Network.TESTNET;
301
+ case "devnet":
302
+ return tsSdk.Network.DEVNET;
303
+ default:
304
+ return tsSdk.Network.TESTNET;
305
+ }
306
+ }
307
+ getAccount() {
308
+ return this.account;
309
+ }
310
+ getClient() {
311
+ return this.client;
312
+ }
313
+ getPrivateKeyHex() {
314
+ return this.privateKeyHex;
315
+ }
316
+ setKeylessConfig(config) {
317
+ this.keylessConfig = config;
318
+ }
319
+ isKeyless() {
320
+ return !!this.keylessConfig;
321
+ }
322
+ };
323
+ var GoogleAuthProvider = class {
324
+ constructor(config) {
325
+ this.clientId = config.clientId;
326
+ this.redirectUri = config.redirectUri;
327
+ }
328
+ /**
329
+ * Initiate Google OAuth login flow
330
+ * Opens Google Sign-In popup
331
+ * @param nonce Optional OIDC nonce for keyless binding
332
+ */
333
+ async login(nonce) {
334
+ try {
335
+ if (typeof window === "undefined") {
336
+ throw new SphereSDKError(
337
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
338
+ "Google OAuth requires a browser environment"
339
+ );
340
+ }
341
+ return new Promise((resolve, reject) => {
342
+ this.loadGoogleIdentityScript().then(() => {
343
+ const uxMode = this.redirectUri ? "redirect" : "popup";
344
+ if (uxMode === "redirect") {
345
+ const nonce2 = Math.random().toString(36).substring(2) + Date.now().toString(36);
346
+ const params = new URLSearchParams({
347
+ client_id: this.clientId,
348
+ redirect_uri: this.redirectUri,
349
+ response_type: "id_token",
350
+ scope: "openid email profile",
351
+ nonce: nonce2,
352
+ prompt: "select_account"
353
+ });
354
+ const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
355
+ window.location.href = authUrl;
356
+ } else {
357
+ const client = google.accounts.oauth2.initTokenClient({
358
+ client_id: this.clientId,
359
+ scope: "email profile openid",
360
+ nonce,
361
+ // Bind the ephemeral key pair via nonce
362
+ callback: async (tokenResponse) => {
363
+ if (tokenResponse.error) {
364
+ reject(new SphereSDKError(
365
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
366
+ `Google login failed: ${tokenResponse.error_description || tokenResponse.error}`
367
+ ));
368
+ return;
369
+ }
370
+ if (tokenResponse && tokenResponse.access_token) {
371
+ try {
372
+ const userInfoResponse = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
373
+ headers: {
374
+ "Authorization": `Bearer ${tokenResponse.access_token}`
375
+ }
376
+ });
377
+ if (!userInfoResponse.ok) {
378
+ throw new Error("Failed to fetch user info from Google");
379
+ }
380
+ const payload = await userInfoResponse.json();
381
+ const authResponse = {
382
+ idToken: tokenResponse.access_token,
383
+ // Use access token
384
+ email: payload.email,
385
+ name: payload.name,
386
+ picture: payload.picture,
387
+ sub: payload.sub
388
+ };
389
+ resolve(authResponse);
390
+ } catch (error) {
391
+ reject(new SphereSDKError(
392
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
393
+ "Failed to retrieve user profile after login",
394
+ error
395
+ ));
396
+ }
397
+ }
398
+ }
399
+ });
400
+ client.requestAccessToken();
401
+ }
402
+ }).catch(reject);
403
+ });
404
+ } catch (error) {
405
+ if (error instanceof SphereSDKError) {
406
+ throw error;
407
+ }
408
+ throw new SphereSDKError(
409
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
410
+ "Failed to initiate Google login",
411
+ error
412
+ );
413
+ }
414
+ }
415
+ /**
416
+ * Initialize Google Identity Services
417
+ * @param callback Credential handler
418
+ * @param nonce Optional OIDC nonce for binding
419
+ */
420
+ async initialize(callback, nonce) {
421
+ await this.loadGoogleIdentityScript();
422
+ google.accounts.id.initialize({
423
+ client_id: this.clientId,
424
+ callback,
425
+ nonce
426
+ });
427
+ }
428
+ /**
429
+ * Handle the credential response from Google
430
+ */
431
+ async handleCredentialResponse(credential) {
432
+ try {
433
+ const payload = jose.decodeJwt(credential);
434
+ const authResponse = {
435
+ idToken: credential,
436
+ email: payload.email,
437
+ name: payload.name,
438
+ picture: payload.picture,
439
+ sub: payload.sub
440
+ };
441
+ if (!authResponse.email || !authResponse.sub) {
442
+ throw new SphereSDKError(
443
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
444
+ "Invalid Google credential: missing required fields"
445
+ );
446
+ }
447
+ return authResponse;
448
+ } catch (error) {
449
+ if (error instanceof SphereSDKError) {
450
+ throw error;
451
+ }
452
+ throw new SphereSDKError(
453
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
454
+ "Failed to process Google credential",
455
+ error
456
+ );
457
+ }
458
+ }
459
+ /**
460
+ * Verify Google ID token (optional, for enhanced security)
461
+ * This should ideally be done server-side
462
+ */
463
+ async verifyToken(idToken) {
464
+ try {
465
+ const JWKS_URI = "https://www.googleapis.com/oauth2/v3/certs";
466
+ const response = await fetch(JWKS_URI);
467
+ const jwks = await response.json();
468
+ await jose.jwtVerify(idToken, async () => {
469
+ return jwks.keys[0];
470
+ });
471
+ return true;
472
+ } catch (error) {
473
+ console.error("Token verification failed:", error);
474
+ return false;
475
+ }
476
+ }
477
+ /**
478
+ * Load Google Identity Services script
479
+ */
480
+ loadGoogleIdentityScript() {
481
+ return new Promise((resolve, reject) => {
482
+ if (typeof google !== "undefined" && google.accounts) {
483
+ resolve();
484
+ return;
485
+ }
486
+ const script = document.createElement("script");
487
+ script.src = "https://accounts.google.com/gsi/client";
488
+ script.async = true;
489
+ script.defer = true;
490
+ script.onload = () => resolve();
491
+ script.onerror = () => reject(
492
+ new SphereSDKError(
493
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
494
+ "Failed to load Google Identity Services"
495
+ )
496
+ );
497
+ document.head.appendChild(script);
498
+ });
499
+ }
500
+ /**
501
+ * Sign out from Google
502
+ */
503
+ async logout() {
504
+ try {
505
+ if (typeof google !== "undefined" && google.accounts) {
506
+ google.accounts.id.disableAutoSelect();
507
+ }
508
+ } catch (error) {
509
+ console.error("Google logout error:", error);
510
+ }
511
+ }
512
+ /**
513
+ * Render Google Sign-In button
514
+ * @param elementId ID of the container element
515
+ * @param options Button customization options
516
+ * @param options Button customization options
517
+ */
518
+ async renderButton(elementId, options) {
519
+ await this.loadGoogleIdentityScript();
520
+ if (options?.callback) {
521
+ google.accounts.id.initialize({
522
+ client_id: this.clientId,
523
+ callback: options.callback,
524
+ nonce: options.nonce
525
+ // Pass nonce to button initialization
526
+ });
527
+ }
528
+ google.accounts.id.renderButton(document.getElementById(elementId), {
529
+ theme: options?.theme || "outline",
530
+ size: options?.size || "large",
531
+ text: options?.text || "signin_with",
532
+ shape: options?.shape || "rectangular",
533
+ width: options?.width
534
+ // Google API accepts pixels as number or string
535
+ });
536
+ }
537
+ };
538
+ var SecureStorage = class {
539
+ constructor(encryptionKey, storagePrefix = "cedra_sdk_") {
540
+ this.encryptionKey = encryptionKey || this.generateEncryptionKey();
541
+ this.storagePrefix = storagePrefix;
542
+ }
543
+ /**
544
+ * Get item from storage and decrypt
545
+ */
546
+ async getItem(key) {
547
+ try {
548
+ const fullKey = this.storagePrefix + key;
549
+ const encryptedData = localStorage.getItem(fullKey);
550
+ if (!encryptedData) {
551
+ return null;
552
+ }
553
+ const bytes = CryptoJS2__default.default.AES.decrypt(encryptedData, this.encryptionKey);
554
+ try {
555
+ const decrypted = bytes.toString(CryptoJS2__default.default.enc.Utf8);
556
+ if (!decrypted) return null;
557
+ return decrypted;
558
+ } catch (e) {
559
+ console.warn(`[SecureStorage] Failed to decrypt ${key}. Key might have changed.`);
560
+ return null;
561
+ }
562
+ } catch (error) {
563
+ console.error("Storage get error:", error);
564
+ return null;
565
+ }
566
+ }
567
+ /**
568
+ * Encrypt and store item
569
+ */
570
+ async setItem(key, value) {
571
+ try {
572
+ const fullKey = this.storagePrefix + key;
573
+ const encrypted = CryptoJS2__default.default.AES.encrypt(
574
+ value,
575
+ this.encryptionKey
576
+ ).toString();
577
+ localStorage.setItem(fullKey, encrypted);
578
+ } catch (error) {
579
+ console.error("Storage set error:", error);
580
+ throw new SphereSDKError(
581
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
582
+ "Failed to store data",
583
+ error
584
+ );
585
+ }
586
+ }
587
+ /**
588
+ * Remove item from storage
589
+ */
590
+ async removeItem(key) {
591
+ try {
592
+ const fullKey = this.storagePrefix + key;
593
+ localStorage.removeItem(fullKey);
594
+ } catch (error) {
595
+ console.error("Storage remove error:", error);
596
+ throw new SphereSDKError(
597
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
598
+ "Failed to remove data from storage",
599
+ error
600
+ );
601
+ }
602
+ }
603
+ /**
604
+ * Clear all SDK storage
605
+ */
606
+ async clear() {
607
+ try {
608
+ const keys = Object.keys(localStorage);
609
+ for (const key of keys) {
610
+ if (key.startsWith(this.storagePrefix)) {
611
+ localStorage.removeItem(key);
612
+ }
613
+ }
614
+ } catch (error) {
615
+ console.error("Storage clear error:", error);
616
+ throw new SphereSDKError(
617
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
618
+ "Failed to clear storage",
619
+ error
620
+ );
621
+ }
622
+ }
623
+ /**
624
+ * Generate encryption key from browser fingerprint
625
+ * This provides basic encryption without requiring user input
626
+ * Note: Not cryptographically secure, but better than plaintext
627
+ */
628
+ generateEncryptionKey() {
629
+ const fingerprint = [
630
+ navigator.userAgent,
631
+ navigator.language,
632
+ (/* @__PURE__ */ new Date()).getTimezoneOffset(),
633
+ screen.width,
634
+ screen.height,
635
+ "cedra-sdk-v1"
636
+ // Version salt
637
+ ].join("|");
638
+ return CryptoJS2__default.default.SHA256(fingerprint).toString();
639
+ }
640
+ /**
641
+ * Check if storage is available
642
+ */
643
+ static isAvailable() {
644
+ try {
645
+ const test = "__storage_test__";
646
+ localStorage.setItem(test, test);
647
+ localStorage.removeItem(test);
648
+ return true;
649
+ } catch {
650
+ return false;
651
+ }
652
+ }
653
+ };
654
+ var SessionManager = class {
655
+ constructor(storage, sessionDurationHours = 24) {
656
+ this.sessionKey = "current_session";
657
+ // in milliseconds
658
+ this.cachedSession = null;
659
+ this.storage = storage;
660
+ this.sessionDuration = sessionDurationHours * 60 * 60 * 1e3;
661
+ }
662
+ /**
663
+ * Get cached session data (synchronous)
664
+ */
665
+ getCachedSession() {
666
+ return this.cachedSession;
667
+ }
668
+ /**
669
+ * Save session data
670
+ */
671
+ async saveSession(data) {
672
+ try {
673
+ const sessionData = {
674
+ ...data,
675
+ expiresAt: Date.now() + this.sessionDuration
676
+ };
677
+ this.cachedSession = sessionData;
678
+ await this.storage.setItem(
679
+ this.sessionKey,
680
+ JSON.stringify(sessionData)
681
+ );
682
+ } catch (error) {
683
+ throw new SphereSDKError(
684
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
685
+ `Google authentication failed: ${error.message}`
686
+ );
687
+ }
688
+ }
689
+ /**
690
+ * Get current session
691
+ * Returns null if session doesn't exist or is expired
692
+ */
693
+ async getSession() {
694
+ try {
695
+ const sessionStr = await this.storage.getItem(this.sessionKey);
696
+ if (!sessionStr) {
697
+ return null;
698
+ }
699
+ const session = JSON.parse(sessionStr);
700
+ this.cachedSession = session;
701
+ if (Date.now() > session.expiresAt) {
702
+ await this.clearSession();
703
+ return null;
704
+ }
705
+ return session;
706
+ } catch (error) {
707
+ console.error("Failed to get session:", error);
708
+ return null;
709
+ }
710
+ }
711
+ /**
712
+ * Clear current session
713
+ */
714
+ async clearSession() {
715
+ this.cachedSession = null;
716
+ await this.storage.removeItem(this.sessionKey);
717
+ }
718
+ /**
719
+ * Check if session is valid
720
+ */
721
+ async isSessionValid() {
722
+ const session = await this.getSession();
723
+ return session !== null;
724
+ }
725
+ /**
726
+ * Refresh session expiration
727
+ */
728
+ async refreshSession() {
729
+ const session = await this.getSession();
730
+ if (session) {
731
+ await this.saveSession({
732
+ encryptedWallet: session.encryptedWallet,
733
+ userInfo: session.userInfo,
734
+ refreshToken: session.refreshToken
735
+ });
736
+ }
737
+ }
738
+ /**
739
+ * Get time until session expires (in milliseconds)
740
+ */
741
+ async getTimeUntilExpiration() {
742
+ const session = await this.getSession();
743
+ if (!session) {
744
+ return null;
745
+ }
746
+ const timeLeft = session.expiresAt - Date.now();
747
+ return timeLeft > 0 ? timeLeft : 0;
748
+ }
749
+ };
750
+ var KeyDerivation = class {
751
+ // 256 bits for Ed25519
752
+ /**
753
+ * Derive a private key from user ID and salt
754
+ * @param options Key derivation options
755
+ * @returns Hex-encoded private key (64 characters)
756
+ */
757
+ static derivePrivateKey(options) {
758
+ try {
759
+ const { userId, salt, iterations = this.DEFAULT_ITERATIONS } = options;
760
+ if (!userId || userId.length === 0) {
761
+ throw new SphereSDKError(
762
+ "KEY_DERIVATION_FAILED" /* KEY_DERIVATION_FAILED */,
763
+ "User ID is required for key derivation"
764
+ );
765
+ }
766
+ if (!salt || salt.length < 16) {
767
+ throw new SphereSDKError(
768
+ "KEY_DERIVATION_FAILED" /* KEY_DERIVATION_FAILED */,
769
+ "Salt must be at least 16 characters"
770
+ );
771
+ }
772
+ const derivedKey = CryptoJS2__default.default.PBKDF2(userId, salt, {
773
+ keySize: this.KEY_LENGTH / 4,
774
+ // CryptoJS uses 32-bit words
775
+ iterations,
776
+ hasher: CryptoJS2__default.default.algo.SHA256
777
+ });
778
+ const privateKeyHex = derivedKey.toString(CryptoJS2__default.default.enc.Hex);
779
+ if (privateKeyHex.length !== 64) {
780
+ throw new SphereSDKError(
781
+ "KEY_DERIVATION_FAILED" /* KEY_DERIVATION_FAILED */,
782
+ "Derived key has invalid length"
783
+ );
784
+ }
785
+ return privateKeyHex;
786
+ } catch (error) {
787
+ if (error instanceof SphereSDKError) {
788
+ throw error;
789
+ }
790
+ throw new SphereSDKError(
791
+ "KEY_DERIVATION_FAILED" /* KEY_DERIVATION_FAILED */,
792
+ "Failed to derive private key",
793
+ error
794
+ );
795
+ }
796
+ }
797
+ /**
798
+ * Generate a deterministic salt from app name and user email
799
+ * This ensures the same user gets the same wallet across devices
800
+ * @param appName Application name
801
+ * @param userEmail User's email address
802
+ * @returns Deterministic salt string
803
+ */
804
+ static generateDeterministicSalt(appName, userEmail) {
805
+ const normalizedApp = appName.trim().toLowerCase();
806
+ const normalizedEmail = userEmail.trim().toLowerCase();
807
+ const combined = `${normalizedApp}:${normalizedEmail}:sphere-wallet-v1`;
808
+ const hash = CryptoJS2__default.default.SHA256(combined);
809
+ return hash.toString(CryptoJS2__default.default.enc.Hex);
810
+ }
811
+ /**
812
+ * Validate a private key format
813
+ * @param privateKey Hex-encoded private key
814
+ * @returns True if valid
815
+ */
816
+ static isValidPrivateKey(privateKey) {
817
+ const hexRegex = /^[0-9a-fA-F]{64}$/;
818
+ return hexRegex.test(privateKey);
819
+ }
820
+ /**
821
+ * Securely clear sensitive data from memory
822
+ * @param data Sensitive string to clear
823
+ */
824
+ static clearSensitiveData(data) {
825
+ if (data) {
826
+ data = "0".repeat(data.length);
827
+ }
828
+ }
829
+ /**
830
+ * Generates a temporary ephemeral key pair for the session
831
+ * @returns A fresh Ed25519 account/keypair
832
+ */
833
+ static generateEphemeralKeyPair() {
834
+ return tsSdk.Account.generate();
835
+ }
836
+ /**
837
+ * Computes an OIDC-compliant nonce hash to bind the session key
838
+ * @param publicKey Ephemeral Public Key (hex or string)
839
+ * @param blinding A random blinding factor (hex)
840
+ * @param expiry Expiration timestamp (optional)
841
+ * @returns SHA256 hash of the nonce commitment
842
+ */
843
+ static computeNonce(publicKey, blinding, expiry = 0) {
844
+ const combined = `${publicKey}:${blinding}:${expiry}`;
845
+ const hash = CryptoJS2__default.default.SHA256(combined);
846
+ return hash.toString(CryptoJS2__default.default.enc.Hex);
847
+ }
848
+ };
849
+ KeyDerivation.DEFAULT_ITERATIONS = 1e5;
850
+ KeyDerivation.KEY_LENGTH = 32;
851
+
852
+ // src/core/constants.ts
853
+ var DEFAULT_APP_NAME = "Sphere Connect";
854
+ var DEFAULT_STORAGE_KEY = "sphere-connect-v1-secure-key";
855
+ var SphereAccountAbstraction = class extends EventEmitter {
856
+ constructor(config) {
857
+ super();
858
+ this.currentWallet = null;
859
+ this.initialized = false;
860
+ this.appName = DEFAULT_APP_NAME;
861
+ this.storageKey = DEFAULT_STORAGE_KEY;
862
+ if (!config.googleClientId) {
863
+ throw new SphereSDKError(
864
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
865
+ "Google Client ID is required for initializing the Sphere SDK"
866
+ );
867
+ }
868
+ this.config = {
869
+ network: config.network || "testnet",
870
+ googleClientId: config.googleClientId,
871
+ rpcEndpoint: config.rpcEndpoint,
872
+ indexerUrl: config.indexerUrl,
873
+ redirectUri: config.redirectUri
874
+ };
875
+ const rpc = this.config.rpcEndpoint;
876
+ const cedraConfig = new tsSdk.CedraConfig({
877
+ network: this.config.network,
878
+ fullnode: rpc
879
+ });
880
+ this.cedra = new tsSdk.Cedra(cedraConfig);
881
+ this.authProvider = new GoogleAuthProvider({
882
+ clientId: this.config.googleClientId,
883
+ redirectUri: this.config.redirectUri
884
+ });
885
+ this.storage = new SecureStorage(this.storageKey);
886
+ this.sessionManager = new SessionManager(this.storage, 24);
887
+ }
888
+ async initialize() {
889
+ if (this.initialized) return;
890
+ try {
891
+ await this.restoreSession();
892
+ this.initialized = true;
893
+ this.emit("initialized");
894
+ } catch (error) {
895
+ console.error("Sphere SDK initialization error:", error);
896
+ this.initialized = true;
897
+ }
898
+ }
899
+ async loginWithGoogle() {
900
+ try {
901
+ if (!this.initialized) await this.initialize();
902
+ const googleUser = await this.authProvider.login();
903
+ if (!googleUser || !googleUser.sub || !googleUser.email) {
904
+ return null;
905
+ }
906
+ const salt = KeyDerivation.generateDeterministicSalt(this.appName, googleUser.email);
907
+ const privateKeyHex = KeyDerivation.derivePrivateKey({
908
+ userId: googleUser.sub,
909
+ salt,
910
+ iterations: 1e5
911
+ });
912
+ const wallet = new SphereWallet(
913
+ this.cedra,
914
+ privateKeyHex,
915
+ this.config.network,
916
+ this.config.rpcEndpoint,
917
+ this.config.indexerUrl
918
+ );
919
+ const encryptedWallet = this.encryptWalletData(privateKeyHex);
920
+ await this.sessionManager.saveSession({
921
+ encryptedWallet,
922
+ userInfo: {
923
+ email: googleUser.email,
924
+ name: googleUser.name,
925
+ picture: googleUser.picture
926
+ }
927
+ });
928
+ this.currentWallet = wallet;
929
+ this.emit("auth_success", { wallet, user: googleUser });
930
+ return wallet;
931
+ } catch (error) {
932
+ throw new SphereSDKError(
933
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
934
+ `Google authentication failed: ${error.message}`
935
+ );
936
+ }
937
+ }
938
+ async restoreSession() {
939
+ try {
940
+ const session = await this.sessionManager.getSession();
941
+ if (session && session.expiresAt > Date.now()) {
942
+ const privateKeyHex = this.decryptWalletData(session.encryptedWallet);
943
+ if (!privateKeyHex) return null;
944
+ const wallet = new SphereWallet(
945
+ this.cedra,
946
+ privateKeyHex,
947
+ this.config.network,
948
+ this.config.rpcEndpoint,
949
+ this.config.indexerUrl
950
+ );
951
+ this.currentWallet = wallet;
952
+ this.emit("auth_success", { wallet, method: "restored" });
953
+ return wallet;
954
+ }
955
+ } catch (error) {
956
+ console.error("Session restoration failed:", error);
957
+ }
958
+ return null;
959
+ }
960
+ async handleGoogleResponse(credential) {
961
+ try {
962
+ if (!this.initialized) await this.initialize();
963
+ const googleUser = await this.authProvider.handleCredentialResponse(credential);
964
+ const salt = KeyDerivation.generateDeterministicSalt(this.appName, googleUser.email);
965
+ const privateKeyHex = KeyDerivation.derivePrivateKey({
966
+ userId: googleUser.sub,
967
+ salt,
968
+ iterations: 1e5
969
+ });
970
+ const wallet = new SphereWallet(
971
+ this.cedra,
972
+ privateKeyHex,
973
+ this.config.network,
974
+ this.config.rpcEndpoint,
975
+ this.config.indexerUrl
976
+ );
977
+ const encryptedWallet = this.encryptWalletData(privateKeyHex);
978
+ await this.sessionManager.saveSession({
979
+ encryptedWallet,
980
+ userInfo: {
981
+ email: googleUser.email,
982
+ name: googleUser.name,
983
+ picture: googleUser.picture
984
+ }
985
+ });
986
+ this.currentWallet = wallet;
987
+ this.emit("auth_success", { wallet, user: googleUser });
988
+ return wallet;
989
+ } catch (error) {
990
+ throw new SphereSDKError(
991
+ "AUTHENTICATION_FAILED" /* AUTHENTICATION_FAILED */,
992
+ `Failed to handle Google response: ${error.message}`
993
+ );
994
+ }
995
+ }
996
+ async logout() {
997
+ await this.authProvider.logout();
998
+ await this.sessionManager.clearSession();
999
+ if (this.currentWallet) {
1000
+ await this.currentWallet.disconnect();
1001
+ }
1002
+ this.currentWallet = null;
1003
+ this.emit("logout");
1004
+ }
1005
+ isAuthenticated() {
1006
+ return this.currentWallet !== null;
1007
+ }
1008
+ getCurrentWallet() {
1009
+ return this.currentWallet;
1010
+ }
1011
+ getUserEmail() {
1012
+ const session = this.sessionManager.getCachedSession();
1013
+ return session?.userInfo.email || null;
1014
+ }
1015
+ getEphemeralPublicKey() {
1016
+ return this.currentWallet?.getPublicKey() || null;
1017
+ }
1018
+ async updateNetwork(network, rpcEndpoint) {
1019
+ this.config.network = network;
1020
+ this.config.rpcEndpoint = rpcEndpoint;
1021
+ const cedraConfig = new tsSdk.CedraConfig({
1022
+ network,
1023
+ fullnode: rpcEndpoint
1024
+ });
1025
+ this.cedra = new tsSdk.Cedra(cedraConfig);
1026
+ if (this.currentWallet) {
1027
+ this.currentWallet.updateNetwork(network, rpcEndpoint);
1028
+ }
1029
+ this.emit("network_changed", { network, rpcEndpoint });
1030
+ }
1031
+ getIndexerUrl() {
1032
+ return this.config.indexerUrl;
1033
+ }
1034
+ // Internal helpers for encryption
1035
+ encryptWalletData(privateKeyHex) {
1036
+ return CryptoJS2__default.default.AES.encrypt(privateKeyHex, this.storageKey).toString();
1037
+ }
1038
+ decryptWalletData(encryptedData) {
1039
+ try {
1040
+ const bytes = CryptoJS2__default.default.AES.decrypt(encryptedData, this.storageKey);
1041
+ return bytes.toString(CryptoJS2__default.default.enc.Utf8);
1042
+ } catch (error) {
1043
+ console.warn("[Sphere] Failed to decrypt wallet data");
1044
+ return "";
1045
+ }
1046
+ }
1047
+ // EventEmitter overrides to satisfy interface
1048
+ on(event, listener) {
1049
+ return super.on(event, listener);
1050
+ }
1051
+ off(event, listener) {
1052
+ return super.off(event, listener);
1053
+ }
1054
+ };
1055
+ var SphereContext = react.createContext(void 0);
1056
+ var SphereProvider = ({ children, config }) => {
1057
+ const [sdk] = react.useState(() => new SphereAccountAbstraction(config));
1058
+ const [wallet, setWallet] = react.useState(null);
1059
+ const [walletInfo, setWalletInfo] = react.useState(null);
1060
+ const [balance, setBalance] = react.useState(null);
1061
+ const [email, setEmail] = react.useState(null);
1062
+ const [isLoading, setIsLoading] = react.useState(true);
1063
+ const [error, setError] = react.useState(null);
1064
+ const refreshData = react.useCallback(async (activeWallet) => {
1065
+ try {
1066
+ const [info, bal] = await Promise.all([
1067
+ activeWallet.getAccountInfo(),
1068
+ activeWallet.getBalance()
1069
+ ]);
1070
+ setWalletInfo(info);
1071
+ setBalance(bal);
1072
+ } catch (err) {
1073
+ console.error("Failed to refresh data:", err);
1074
+ }
1075
+ }, []);
1076
+ react.useEffect(() => {
1077
+ const onAuth = ({ wallet: wallet2 }) => {
1078
+ setWallet(wallet2);
1079
+ setEmail(sdk.getUserEmail());
1080
+ refreshData(wallet2);
1081
+ };
1082
+ const onLogout = () => {
1083
+ setWallet(null);
1084
+ setEmail(null);
1085
+ setWalletInfo(null);
1086
+ setBalance(null);
1087
+ };
1088
+ sdk.on("auth_success", onAuth);
1089
+ sdk.on("logout", onLogout);
1090
+ const init = async () => {
1091
+ try {
1092
+ await sdk.initialize();
1093
+ const restored = await sdk.restoreSession();
1094
+ if (restored) {
1095
+ setWallet(restored);
1096
+ setEmail(sdk.getUserEmail());
1097
+ await refreshData(restored);
1098
+ }
1099
+ } catch (err) {
1100
+ console.error("SDK Init error:", err);
1101
+ setError(err.message || "Initialization failed");
1102
+ } finally {
1103
+ setIsLoading(false);
1104
+ }
1105
+ };
1106
+ init();
1107
+ return () => {
1108
+ sdk.off("auth_success", onAuth);
1109
+ sdk.off("logout", onLogout);
1110
+ };
1111
+ }, [sdk, refreshData]);
1112
+ react.useEffect(() => {
1113
+ if (!wallet) return void 0;
1114
+ const pollInterval = setInterval(() => {
1115
+ refreshData(wallet);
1116
+ }, 1e4);
1117
+ return () => clearInterval(pollInterval);
1118
+ }, [wallet, refreshData]);
1119
+ const handleAuthSuccess = react.useCallback(async (newWallet) => {
1120
+ setWallet(newWallet);
1121
+ await refreshData(newWallet);
1122
+ }, [refreshData]);
1123
+ const login = async () => {
1124
+ setError(null);
1125
+ try {
1126
+ await sdk.loginWithGoogle();
1127
+ } catch (err) {
1128
+ console.error("Sphere Login Error:", err);
1129
+ setError(err.message || "Login failed");
1130
+ throw err;
1131
+ }
1132
+ };
1133
+ const logout = async () => {
1134
+ try {
1135
+ await sdk.logout();
1136
+ } catch (err) {
1137
+ setError(err.message || "Logout failed");
1138
+ throw err;
1139
+ }
1140
+ };
1141
+ return /* @__PURE__ */ jsxRuntime.jsx(
1142
+ SphereContext.Provider,
1143
+ {
1144
+ value: {
1145
+ sdk,
1146
+ wallet,
1147
+ walletInfo,
1148
+ balance,
1149
+ email,
1150
+ indexerUrl: sdk.getIndexerUrl(),
1151
+ isAuthenticated: !!wallet,
1152
+ isLoading,
1153
+ error,
1154
+ login,
1155
+ logout,
1156
+ setIsLoading,
1157
+ refreshData: async () => {
1158
+ if (wallet) await refreshData(wallet);
1159
+ },
1160
+ handleAuthSuccess
1161
+ },
1162
+ children
1163
+ }
1164
+ );
1165
+ };
1166
+ var useSphere = () => {
1167
+ const context = react.useContext(SphereContext);
1168
+ if (context === void 0) {
1169
+ throw new Error("useSphere must be used within a SphereProvider");
1170
+ }
1171
+ return context;
1172
+ };
1173
+ var SphereModal = ({ isOpen, onClose }) => {
1174
+ const { login, isAuthenticated, isLoading, error } = useSphere();
1175
+ const [localLoading, setLocalLoading] = react.useState(false);
1176
+ react.useEffect(() => {
1177
+ if (isAuthenticated) {
1178
+ onClose();
1179
+ }
1180
+ }, [isAuthenticated, onClose]);
1181
+ const handleLogin = async () => {
1182
+ try {
1183
+ setLocalLoading(true);
1184
+ await login();
1185
+ } catch (err) {
1186
+ console.error("Sphere Login Error:", err);
1187
+ } finally {
1188
+ setLocalLoading(false);
1189
+ }
1190
+ };
1191
+ if (!isOpen) return null;
1192
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.overlay, onClick: (e) => e.target === e.currentTarget && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.modal, children: [
1193
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.header, children: [
1194
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: 32 } }),
1195
+ " ",
1196
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles.closeBtn, onClick: onClose, "aria-label": "Close", children: "\xD7" })
1197
+ ] }),
1198
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.content, children: [
1199
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: styles.title, children: "Connect to Sphere" }),
1200
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles.description, children: "Experience the next generation of account abstraction. Secure, fast, and effortless." }),
1201
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.errorBanner, children: error }),
1202
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.actionContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
1203
+ "button",
1204
+ {
1205
+ style: {
1206
+ ...styles.customButton,
1207
+ opacity: isLoading || localLoading ? 0.7 : 1,
1208
+ cursor: isLoading || localLoading ? "not-allowed" : "pointer"
1209
+ },
1210
+ onClick: handleLogin,
1211
+ disabled: isLoading || localLoading,
1212
+ children: [
1213
+ isLoading || localLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.spinner }) : /* @__PURE__ */ jsxRuntime.jsx(
1214
+ "img",
1215
+ {
1216
+ src: "https://www.gstatic.com/images/branding/product/1x/gsa_512dp.png",
1217
+ alt: "Google",
1218
+ style: styles.googleIcon
1219
+ }
1220
+ ),
1221
+ isLoading || localLoading ? "Connecting..." : "Continue with Google"
1222
+ ]
1223
+ }
1224
+ ) }),
1225
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1226
+ @keyframes sphere-spin {
1227
+ 0% { transform: rotate(0deg); }
1228
+ 100% { transform: rotate(360deg); }
1229
+ }
1230
+ ` }),
1231
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.footer, children: [
1232
+ "Securely powered by ",
1233
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Sphere SDK" })
1234
+ ] })
1235
+ ] })
1236
+ ] }) });
1237
+ };
1238
+ var styles = {
1239
+ overlay: {
1240
+ position: "fixed",
1241
+ top: 0,
1242
+ left: 0,
1243
+ right: 0,
1244
+ bottom: 0,
1245
+ backgroundColor: "transparent",
1246
+ display: "flex",
1247
+ alignItems: "center",
1248
+ justifyContent: "center",
1249
+ zIndex: 9999,
1250
+ padding: "20px"
1251
+ },
1252
+ modal: {
1253
+ backgroundColor: "#0c0c0c",
1254
+ color: "#ffffff",
1255
+ width: "90%",
1256
+ maxWidth: "400px",
1257
+ aspectRatio: "1/1",
1258
+ borderRadius: "0",
1259
+ position: "relative",
1260
+ boxShadow: "0 0 0 1px #222, 0 25px 60px rgba(0, 0, 0, 0.7)",
1261
+ overflow: "hidden",
1262
+ fontFamily: "Inter, -apple-system, system-ui, sans-serif",
1263
+ display: "flex",
1264
+ flexDirection: "column"
1265
+ },
1266
+ header: {
1267
+ display: "flex",
1268
+ justifyContent: "space-between",
1269
+ alignItems: "center",
1270
+ padding: "24px 24px 0 24px"
1271
+ },
1272
+ closeBtn: {
1273
+ background: "rgba(255, 255, 255, 0.05)",
1274
+ border: "none",
1275
+ color: "#888",
1276
+ fontSize: "24px",
1277
+ cursor: "pointer",
1278
+ lineHeight: 1,
1279
+ width: "32px",
1280
+ height: "32px",
1281
+ borderRadius: "50%",
1282
+ display: "flex",
1283
+ alignItems: "center",
1284
+ justifyContent: "center",
1285
+ transition: "all 0.2s"
1286
+ },
1287
+ content: {
1288
+ display: "flex",
1289
+ flexDirection: "column",
1290
+ padding: "20px",
1291
+ alignItems: "center",
1292
+ flex: 1,
1293
+ justifyContent: "center",
1294
+ width: "100%",
1295
+ boxSizing: "border-box"
1296
+ },
1297
+ title: {
1298
+ fontSize: "1.5rem",
1299
+ fontWeight: "700",
1300
+ color: "#ffffff",
1301
+ textAlign: "center",
1302
+ marginBottom: "10px",
1303
+ margin: 0
1304
+ },
1305
+ description: {
1306
+ fontSize: "0.7rem",
1307
+ color: "#94a3b8",
1308
+ textAlign: "center",
1309
+ lineHeight: "1.5",
1310
+ marginBottom: "32px",
1311
+ margin: 0
1312
+ },
1313
+ errorBanner: {
1314
+ backgroundColor: "rgba(239, 68, 68, 0.1)",
1315
+ border: "1px solid rgba(239, 68, 68, 0.2)",
1316
+ color: "#f87171",
1317
+ padding: "12px 16px",
1318
+ borderRadius: "16px",
1319
+ fontSize: "13px",
1320
+ marginBottom: "24px",
1321
+ textAlign: "center",
1322
+ width: "100%"
1323
+ },
1324
+ actionContainer: {
1325
+ display: "flex",
1326
+ flexDirection: "column",
1327
+ width: "100%"
1328
+ },
1329
+ customButton: {
1330
+ display: "flex",
1331
+ alignItems: "center",
1332
+ justifyContent: "center",
1333
+ gap: "12px",
1334
+ width: "100%",
1335
+ height: "52px",
1336
+ backgroundColor: "#0c0c0c",
1337
+ border: "1px solid #333",
1338
+ borderRadius: "0",
1339
+ cursor: "pointer",
1340
+ fontSize: "15px",
1341
+ fontWeight: "600",
1342
+ color: "#ffffff",
1343
+ transition: "transform 0.1s, opacity 0.2s",
1344
+ boxSizing: "border-box"
1345
+ },
1346
+ googleIcon: {
1347
+ width: "20px",
1348
+ height: "20px"
1349
+ },
1350
+ spinner: {
1351
+ width: "20px",
1352
+ height: "20px",
1353
+ border: "2px solid rgba(255, 255, 255, 0.1)",
1354
+ borderTop: "2px solid #ffffff",
1355
+ borderRadius: "50%",
1356
+ animation: "sphere-spin 0.8s linear infinite"
1357
+ },
1358
+ footer: {
1359
+ marginTop: "32px",
1360
+ textAlign: "center",
1361
+ fontSize: "11px",
1362
+ color: "#475569",
1363
+ letterSpacing: "0.5px"
1364
+ }
1365
+ };
1366
+
1367
+ Object.defineProperty(exports, "Account", {
1368
+ enumerable: true,
1369
+ get: function () { return tsSdk.Account; }
1370
+ });
1371
+ Object.defineProperty(exports, "Cedra", {
1372
+ enumerable: true,
1373
+ get: function () { return tsSdk.Cedra; }
1374
+ });
1375
+ Object.defineProperty(exports, "CedraConfig", {
1376
+ enumerable: true,
1377
+ get: function () { return tsSdk.CedraConfig; }
1378
+ });
1379
+ Object.defineProperty(exports, "CedraNetwork", {
1380
+ enumerable: true,
1381
+ get: function () { return tsSdk.Network; }
1382
+ });
1383
+ Object.defineProperty(exports, "Ed25519PrivateKey", {
1384
+ enumerable: true,
1385
+ get: function () { return tsSdk.Ed25519PrivateKey; }
1386
+ });
1387
+ Object.defineProperty(exports, "PrivateKey", {
1388
+ enumerable: true,
1389
+ get: function () { return tsSdk.PrivateKey; }
1390
+ });
1391
+ Object.defineProperty(exports, "PrivateKeyVariants", {
1392
+ enumerable: true,
1393
+ get: function () { return tsSdk.PrivateKeyVariants; }
1394
+ });
1395
+ exports.ErrorCode = ErrorCode;
1396
+ exports.GoogleAuthProvider = GoogleAuthProvider;
1397
+ exports.KeyDerivation = KeyDerivation;
1398
+ exports.SecureStorage = SecureStorage;
1399
+ exports.SessionManager = SessionManager;
1400
+ exports.SphereAccountAbstraction = SphereAccountAbstraction;
1401
+ exports.SphereModal = SphereModal;
1402
+ exports.SphereProvider = SphereProvider;
1403
+ exports.SphereSDKError = SphereSDKError;
1404
+ exports.SphereWallet = SphereWallet;
1405
+ exports.useSphere = useSphere;
1406
+ //# sourceMappingURL=index.js.map
1407
+ //# sourceMappingURL=index.js.map