@lumiapassport/ui-kit 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,434 @@
1
+ # @lumiapassport/ui-kit
2
+
3
+ React UI components and hooks for Lumia Passport - a secure, user-friendly authentication and Account Abstraction wallet solution with MPC (Multi-Party Computation) key management.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Secure Authentication** - Multiple auth methods: Email, Passkey, Telegram, Wallet connect
8
+ - 🔑 **MPC Key Management** - Distributed key generation with iframe isolation
9
+ - 💼 **Account Abstraction** - ERC-4337 compliant smart contract wallets
10
+ - 🎨 **Pre-built UI Components** - Ready-to-use React components with customizable themes
11
+ - ⚡ **Easy Integration** - Just wrap your app with `LumiaPassportProvider`
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @lumiapassport/ui-kit @lumiapassport/core
17
+ # or
18
+ pnpm add @lumiapassport/ui-kit @lumiapassport/core
19
+ # or
20
+ yarn add @lumiapassport/ui-kit @lumiapassport/core
21
+ ```
22
+
23
+ ### Peer Dependencies
24
+
25
+ The following packages are required as peer dependencies:
26
+
27
+ ```bash
28
+ npm install react react-dom viem wagmi @tanstack/react-query
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Wrap your app with `LumiaPassportProvider`
34
+
35
+ ```tsx
36
+ import { LumiaPassportProvider } from '@lumiapassport/ui-kit';
37
+ import '@lumiapassport/ui-kit/dist/styles.css';
38
+
39
+ function App() {
40
+ return (
41
+ <LumiaPassportProvider
42
+ config={{
43
+ projectId: 'your-project-id', // Get from Lumia Passport Dashboard
44
+ services: {
45
+ tssUrl: 'https://api.lumiapassport.com/tss',
46
+ bundlerUrl: 'https://api.lumiapassport.com/rundler',
47
+ shareVaultUrl: 'https://api.lumiapassport.com/vault',
48
+ }
49
+ }}
50
+ >
51
+ <YourApp />
52
+ </LumiaPassportProvider>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ### 2. Add the Connect Button
58
+
59
+ ```tsx
60
+ import { ConnectWalletButton } from '@lumiapassport/ui-kit';
61
+
62
+ function YourApp() {
63
+ return (
64
+ <div>
65
+ <h1>My App</h1>
66
+ <ConnectWalletButton />
67
+ </div>
68
+ );
69
+ }
70
+ ```
71
+
72
+ That's it! The `ConnectWalletButton` provides a complete authentication UI with wallet management.
73
+
74
+ ## Configuration Options
75
+
76
+ ### Basic Configuration
77
+
78
+ ```tsx
79
+ <LumiaPassportProvider
80
+ config={{
81
+ projectId: 'your-project-id', // Required
82
+
83
+ // Optional: Service URLs (defaults to production)
84
+ services: {
85
+ tssUrl: 'https://api.lumiapassport.com/tss',
86
+ bundlerUrl: 'https://api.lumiapassport.com/rundler',
87
+ shareVaultUrl: 'https://api.lumiapassport.com/vault',
88
+ iframeUrl: 'https://auth.lumiapassport.com',
89
+ },
90
+
91
+ // Optional: Custom RPC and network
92
+ rpcUrl: 'https://beam-rpc.lumia.org',
93
+ explorerUrl: 'https://beam-explorer.lumia.org',
94
+
95
+ // Optional: Custom smart contract addresses
96
+ aaFactoryAddress: '0x...',
97
+ paymasterAddress: '0x...',
98
+ }}
99
+ >
100
+ ```
101
+
102
+ ### Advanced Configuration
103
+
104
+ ```tsx
105
+ <LumiaPassportProvider
106
+ config={{
107
+ projectId: 'your-project-id',
108
+
109
+ // Authentication providers
110
+ authProviders: {
111
+ email: true, // Email OTP
112
+ passkey: true, // Passkey/WebAuthn
113
+ telegram: true, // Telegram Mini App
114
+ wallet: true, // External wallet connection
115
+ },
116
+
117
+ // UI customization
118
+ theme: {
119
+ mode: 'dark', // 'light' | 'dark' | 'auto'
120
+ primaryColor: '#6366f1', // Custom brand color
121
+ },
122
+
123
+ // Features
124
+ features: {
125
+ backup: true, // Enable key backup/recovery
126
+ mpcSecurity: true, // Enable MPC iframe isolation
127
+ },
128
+ }}
129
+ >
130
+ ```
131
+
132
+ ## Using Hooks
133
+
134
+ ### useAuth - Authentication State
135
+
136
+ ```tsx
137
+ import { useAuth } from '@lumiapassport/ui-kit';
138
+
139
+ function MyComponent() {
140
+ const {
141
+ user, // Current user info
142
+ isAuthenticated, // Auth status
143
+ login, // Login function
144
+ logout, // Logout function
145
+ loading, // Loading state
146
+ } = useAuth();
147
+
148
+ if (loading) return <div>Loading...</div>;
149
+
150
+ if (!isAuthenticated) {
151
+ return <button onClick={() => login()}>Sign In</button>;
152
+ }
153
+
154
+ return (
155
+ <div>
156
+ <p>Welcome, {user.userId}</p>
157
+ <button onClick={() => logout()}>Sign Out</button>
158
+ </div>
159
+ );
160
+ }
161
+ ```
162
+
163
+ ### useWallet - Wallet Operations
164
+
165
+ ```tsx
166
+ import { useWallet } from '@lumiapassport/ui-kit';
167
+
168
+ function SendTransaction() {
169
+ const { address, sendTransaction, balance } = useWallet();
170
+
171
+ const handleSend = async () => {
172
+ const hash = await sendTransaction({
173
+ to: '0x...',
174
+ value: '0.1', // ETH amount
175
+ });
176
+ console.log('Transaction hash:', hash);
177
+ };
178
+
179
+ return (
180
+ <div>
181
+ <p>Address: {address}</p>
182
+ <p>Balance: {balance} ETH</p>
183
+ <button onClick={handleSend}>Send Transaction</button>
184
+ </div>
185
+ );
186
+ }
187
+ ```
188
+
189
+ ### useSendTransaction - Send Transactions
190
+
191
+ ```tsx
192
+ import { useSendTransaction } from '@lumiapassport/ui-kit';
193
+
194
+ function TransactionExample() {
195
+ const { sendTransaction, isPending } = useSendTransaction();
196
+
197
+ const handleSend = async () => {
198
+ try {
199
+ const userOpHash = await sendTransaction({
200
+ to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
201
+ value: '1000000000000000000', // 1 ETH in wei
202
+ data: '0x', // Optional contract call data
203
+ });
204
+ console.log('UserOp hash:', userOpHash);
205
+ } catch (error) {
206
+ console.error('Transaction failed:', error);
207
+ }
208
+ };
209
+
210
+ return (
211
+ <div>
212
+ <button onClick={handleSend} disabled={isPending}>
213
+ {isPending ? 'Sending...' : 'Send Transaction'}
214
+ </button>
215
+ </div>
216
+ );
217
+ }
218
+ ```
219
+
220
+ ### prepareUserOperation - Prepare for Backend Submission
221
+
222
+ ```tsx
223
+ import { prepareUserOperation, useLumiaSession } from '@lumiapassport/ui-kit';
224
+
225
+ function BackendSubmissionExample() {
226
+ const { session } = useLumiaSession();
227
+
228
+ const handlePrepare = async () => {
229
+ if (!session) return;
230
+
231
+ // Prepare and sign UserOp without sending to bundler
232
+ const { userOp, userOpHash } = await prepareUserOperation(
233
+ session,
234
+ '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // to
235
+ '1000000000000000000', // 1 ETH in wei
236
+ '0x', // data
237
+ 'standard', // fee type: 'economy' | 'standard' | 'fast'
238
+ 'v0.7' // EntryPoint version
239
+ );
240
+
241
+ // Send to backend for validation and submission
242
+ await fetch('/api/submit-transaction', {
243
+ method: 'POST',
244
+ headers: { 'Content-Type': 'application/json' },
245
+ body: JSON.stringify({
246
+ userOp,
247
+ userOpHash,
248
+ ownerAddress: session.ownerAddress // for signature verification
249
+ }),
250
+ });
251
+ };
252
+
253
+ return (
254
+ <button onClick={handlePrepare}>
255
+ Prepare & Send to Backend
256
+ </button>
257
+ );
258
+ }
259
+ ```
260
+
261
+ **Backend example (using @lumiapassport/core):**
262
+
263
+ ```typescript
264
+ import { sendUserOperationRaw } from '@lumiapassport/core';
265
+ import { recoverAddress } from 'viem';
266
+
267
+ // Receive from frontend
268
+ const { userOp, userOpHash, ownerAddress } = await request.json();
269
+
270
+ // Verify signature
271
+ const recoveredAddress = await recoverAddress({
272
+ hash: userOpHash,
273
+ signature: userOp.signature,
274
+ });
275
+
276
+ if (recoveredAddress.toLowerCase() !== ownerAddress.toLowerCase()) {
277
+ throw new Error('Invalid signature');
278
+ }
279
+
280
+ // Submit to bundler
281
+ const txHash = await sendUserOperationRaw(userOp);
282
+ return { success: true, txHash };
283
+ ```
284
+
285
+ ## Components
286
+
287
+ ### ConnectWalletButton
288
+
289
+ Pre-built button with authentication modal.
290
+
291
+ ```tsx
292
+ <ConnectWalletButton
293
+ className="custom-class"
294
+ onConnect={(user) => console.log('Connected:', user)}
295
+ onDisconnect={() => console.log('Disconnected')}
296
+ />
297
+ ```
298
+
299
+ ### Custom Authentication Flow
300
+
301
+ ```tsx
302
+ import { AuthModal, useAuthModal } from '@lumiapassport/ui-kit';
303
+
304
+ function CustomAuth() {
305
+ const { openAuth } = useAuthModal();
306
+
307
+ return (
308
+ <div>
309
+ <button onClick={() => openAuth()}>
310
+ Custom Sign In
311
+ </button>
312
+ <AuthModal />
313
+ </div>
314
+ );
315
+ }
316
+ ```
317
+
318
+ ## Authentication Methods
319
+
320
+ ### Email OTP
321
+
322
+ Users receive a one-time code via email.
323
+
324
+ ```tsx
325
+ // Configured by default, no additional setup needed
326
+ ```
327
+
328
+ ### Passkey (WebAuthn)
329
+
330
+ Secure biometric authentication with device passkeys.
331
+
332
+ ```tsx
333
+ // Configured by default
334
+ // Users can register passkey after initial login
335
+ ```
336
+
337
+ ### Telegram Mini App
338
+
339
+ Authentication via Telegram for mini apps.
340
+
341
+ ```tsx
342
+ // Requires Telegram bot configuration
343
+ // Set in config:
344
+ config={{
345
+ telegram: {
346
+ botName: 'your_bot_name',
347
+ }
348
+ }}
349
+ ```
350
+
351
+ ### External Wallet
352
+
353
+ Connect existing wallets (MetaMask, WalletConnect, etc.).
354
+
355
+ ```tsx
356
+ // Configured by default
357
+ // Uses RainbowKit for wallet connections
358
+ ```
359
+
360
+ ## Styling
361
+
362
+ ### Using Built-in Themes
363
+
364
+ ```tsx
365
+ import '@lumiapassport/ui-kit/dist/styles.css';
366
+
367
+ <LumiaPassportProvider
368
+ config={{
369
+ projectId: 'your-project-id',
370
+ theme: {
371
+ mode: 'dark', // or 'light', 'auto'
372
+ }
373
+ }}
374
+ >
375
+ ```
376
+
377
+ ### Custom Styling
378
+
379
+ Override CSS variables for custom branding:
380
+
381
+ ```css
382
+ .lumia-scope {
383
+ --lumia-primary: #6366f1;
384
+ --lumia-background: #0f172a;
385
+ --lumia-surface: #1e293b;
386
+ --lumia-text-primary: #f8fafc;
387
+ --lumia-text-secondary: #cbd5e1;
388
+ }
389
+ ```
390
+
391
+ ## TypeScript Support
392
+
393
+ Full TypeScript support with exported types:
394
+
395
+ ```tsx
396
+ import type {
397
+ LumiaPassportConfig,
398
+ User,
399
+ AuthProvider,
400
+ WalletInfo,
401
+ } from '@lumiapassport/ui-kit';
402
+ ```
403
+
404
+ ## Examples
405
+
406
+ Check out the `/examples` directory for complete working examples:
407
+
408
+ - **React + Vite** - Modern React setup with Vite
409
+ - **Next.js** - Next.js App Router integration
410
+ - **React + TypeScript** - Full TypeScript example
411
+
412
+ ## Security
413
+
414
+ - 🔒 **MPC Key Management** - Keys are split between client and server using threshold cryptography
415
+ - 🏝️ **Iframe Isolation** - Sensitive operations run in isolated iframe context
416
+ - 🔐 **No Private Key Exposure** - Private keys never exist in complete form on client
417
+ - ✅ **Non-custodial** - Users maintain full control of their accounts
418
+
419
+ ## Need Help?
420
+
421
+ - 📖 [Documentation](https://docs.lumiapassport.com)
422
+ - 💬 [Discord Community](https://discord.gg/lumia)
423
+ - 🐛 [Report Issues](https://github.com/lumiachain/lumia-passport-sdk/issues)
424
+ - 📧 [Email Support](mailto:support@lumia.org)
425
+
426
+ ## License
427
+
428
+ MIT License - see LICENSE file for details.
429
+
430
+ ## Links
431
+
432
+ - [Website](https://lumiapassport.com)
433
+ - [GitHub](https://github.com/lumiachain/lumia-passport-sdk)
434
+ - [NPM Package](https://www.npmjs.com/package/@lumiapassport/ui-kit)
@@ -783,7 +783,7 @@ var SecureMessenger = class {
783
783
  return;
784
784
  }
785
785
  const response = {
786
- type: "RESPONSE",
786
+ type: "LUMIA_PASSPORT_RESPONSE",
787
787
  messageId,
788
788
  timestamp: Date.now(),
789
789
  data
@@ -800,7 +800,7 @@ var SecureMessenger = class {
800
800
  return;
801
801
  }
802
802
  const response = {
803
- type: "ERROR",
803
+ type: "LUMIA_PASSPORT_ERROR",
804
804
  messageId,
805
805
  timestamp: Date.now(),
806
806
  error
@@ -1597,7 +1597,7 @@ var TokenRefreshApiClient = class {
1597
1597
  }, 3e4);
1598
1598
  const messageHandler = (event) => {
1599
1599
  const message = event.data;
1600
- if (message && message.type === "TOKEN_REFRESHED" && message.messageId === messageId) {
1600
+ if (message && message.type === "LUMIA_PASSPORT_TOKEN_REFRESHED" && message.messageId === messageId) {
1601
1601
  cleanup();
1602
1602
  if (message.accessToken) {
1603
1603
  console.log("[iframe][TokenRefresh] \u2705 Received new token from parent");
@@ -1619,14 +1619,14 @@ var TokenRefreshApiClient = class {
1619
1619
  if (window.parent && window.parent !== window) {
1620
1620
  window.parent.postMessage(
1621
1621
  {
1622
- type: "REQUEST_NEW_TOKEN",
1622
+ type: "LUMIA_PASSPORT_REQUEST_NEW_TOKEN",
1623
1623
  messageId,
1624
1624
  timestamp: Date.now()
1625
1625
  },
1626
1626
  "*"
1627
1627
  // Parent will validate origin
1628
1628
  );
1629
- console.log("[iframe][TokenRefresh] \u{1F4E4} Sent REQUEST_NEW_TOKEN to parent");
1629
+ console.log("[iframe][TokenRefresh] \u{1F4E4} Sent LUMIA_PASSPORT_REQUEST_NEW_TOKEN to parent");
1630
1630
  } else {
1631
1631
  cleanup();
1632
1632
  reject(new Error("No parent window available"));
@@ -2390,7 +2390,7 @@ var SigningManager = class extends TokenRefreshApiClient {
2390
2390
  */
2391
2391
  showIframe() {
2392
2392
  if (window.parent !== window) {
2393
- window.parent.postMessage({ type: "SHOW_IFRAME", timestamp: Date.now() }, "*");
2393
+ window.parent.postMessage({ type: "LUMIA_PASSPORT_SHOW_IFRAME", timestamp: Date.now() }, "*");
2394
2394
  console.log("[iframe][Sign] Requested parent to show iframe");
2395
2395
  }
2396
2396
  }
@@ -2399,7 +2399,7 @@ var SigningManager = class extends TokenRefreshApiClient {
2399
2399
  */
2400
2400
  hideIframe() {
2401
2401
  if (window.parent !== window) {
2402
- window.parent.postMessage({ type: "HIDE_IFRAME", timestamp: Date.now() }, "*");
2402
+ window.parent.postMessage({ type: "LUMIA_PASSPORT_HIDE_IFRAME", timestamp: Date.now() }, "*");
2403
2403
  console.log("[iframe][Sign] Requested parent to hide iframe");
2404
2404
  }
2405
2405
  }
@@ -2511,7 +2511,7 @@ var AuthorizationManager = class {
2511
2511
  */
2512
2512
  showIframe() {
2513
2513
  if (window.parent !== window) {
2514
- window.parent.postMessage({ type: "SHOW_IFRAME", timestamp: Date.now() }, "*");
2514
+ window.parent.postMessage({ type: "LUMIA_PASSPORT_SHOW_IFRAME", timestamp: Date.now() }, "*");
2515
2515
  console.log("[iframe][Auth] Requested parent to show iframe");
2516
2516
  }
2517
2517
  }
@@ -2520,7 +2520,7 @@ var AuthorizationManager = class {
2520
2520
  */
2521
2521
  hideIframe() {
2522
2522
  if (window.parent !== window) {
2523
- window.parent.postMessage({ type: "HIDE_IFRAME", timestamp: Date.now() }, "*");
2523
+ window.parent.postMessage({ type: "LUMIA_PASSPORT_HIDE_IFRAME", timestamp: Date.now() }, "*");
2524
2524
  console.log("[iframe][Auth] Requested parent to hide iframe");
2525
2525
  }
2526
2526
  }
@@ -2655,7 +2655,7 @@ var IframeWallet = class {
2655
2655
  if (window.parent !== window) {
2656
2656
  window.parent.postMessage(
2657
2657
  {
2658
- type: "IFRAME_READY",
2658
+ type: "LUMIA_PASSPORT_IFRAME_READY",
2659
2659
  timestamp: Date.now()
2660
2660
  },
2661
2661
  "*"
@@ -2718,7 +2718,7 @@ var IframeWallet = class {
2718
2718
  this.messenger.sendResponse(
2719
2719
  messageId,
2720
2720
  {
2721
- type: "SDK_AUTH_SUCCESS",
2721
+ type: "LUMIA_PASSPORT_SDK_AUTH_SUCCESS",
2722
2722
  sessionToken
2723
2723
  },
2724
2724
  origin
@@ -2753,7 +2753,7 @@ var IframeWallet = class {
2753
2753
  this.messenger.sendResponse(
2754
2754
  messageId,
2755
2755
  {
2756
- type: "AUTH_SUCCESS",
2756
+ type: "LUMIA_PASSPORT_AUTH_SUCCESS",
2757
2757
  userId,
2758
2758
  address
2759
2759
  },
@@ -2784,7 +2784,7 @@ var IframeWallet = class {
2784
2784
  this.messenger.sendResponse(
2785
2785
  messageId,
2786
2786
  {
2787
- type: "DKG_SUCCESS",
2787
+ type: "LUMIA_PASSPORT_DKG_SUCCESS",
2788
2788
  ownerAddress: result.ownerAddress
2789
2789
  },
2790
2790
  origin
@@ -2817,7 +2817,7 @@ var IframeWallet = class {
2817
2817
  this.messenger.sendResponse(
2818
2818
  messageId,
2819
2819
  {
2820
- type: "SIGNATURE",
2820
+ type: "LUMIA_PASSPORT_SIGNATURE",
2821
2821
  signature
2822
2822
  },
2823
2823
  origin
@@ -2838,7 +2838,7 @@ var IframeWallet = class {
2838
2838
  this.messenger.sendResponse(
2839
2839
  messageId,
2840
2840
  {
2841
- type: "ADDRESS",
2841
+ type: "LUMIA_PASSPORT_ADDRESS",
2842
2842
  address
2843
2843
  },
2844
2844
  origin
@@ -2855,7 +2855,7 @@ var IframeWallet = class {
2855
2855
  this.messenger.sendResponse(
2856
2856
  messageId,
2857
2857
  {
2858
- type: "KEYSHARE_STATUS",
2858
+ type: "LUMIA_PASSPORT_KEYSHARE_STATUS",
2859
2859
  hasKeyshare,
2860
2860
  address
2861
2861
  },
@@ -2876,7 +2876,7 @@ var IframeWallet = class {
2876
2876
  this.messenger.sendResponse(
2877
2877
  messageId,
2878
2878
  {
2879
- type: "TRUSTED_APPS_LIST",
2879
+ type: "LUMIA_PASSPORT_TRUSTED_APPS_LIST",
2880
2880
  apps: trustedApps
2881
2881
  },
2882
2882
  origin
@@ -2896,7 +2896,7 @@ var IframeWallet = class {
2896
2896
  this.messenger.sendResponse(
2897
2897
  messageId,
2898
2898
  {
2899
- type: "TRUSTED_APP_REMOVED",
2899
+ type: "LUMIA_PASSPORT_TRUSTED_APP_REMOVED",
2900
2900
  success: true
2901
2901
  },
2902
2902
  origin