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