shogun-button-react 6.3.1 → 6.3.3
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 +752 -752
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/122.index.js +0 -2
- package/dist/122.index.js.LICENSE.txt +0 -1
- package/dist/47.index.js +0 -2
- package/dist/47.index.js.LICENSE.txt +0 -1
- package/dist/649.index.js +0 -2
- package/dist/649.index.js.LICENSE.txt +0 -1
- package/dist/794.index.js +0 -2
- package/dist/794.index.js.LICENSE.txt +0 -1
package/README.md
CHANGED
|
@@ -1,752 +1,752 @@
|
|
|
1
|
-
# Shogun Button React
|
|
2
|
-
|
|
3
|
-
A comprehensive React component library for seamless integration of Shogun authentication into your applications. This library provides a simple yet powerful way to add multi-method authentication, account management, and real-time data synchronization to your React applications.
|
|
4
|
-
|
|
5
|
-
> **Version 5.0.0** - Compatible with shogun-core ^2.0.0
|
|
6
|
-
|
|
7
|
-
## ✨ Features
|
|
8
|
-
|
|
9
|
-
- 🚀 **Easy Integration** - Simple setup with minimal configuration
|
|
10
|
-
- 🎨 **Customizable UI** - Modern, responsive design with dark mode support
|
|
11
|
-
- 🔒 **Multi-Authentication** - Support for Password, MetaMask, WebAuthn, Nostr, and ZK-Proof
|
|
12
|
-
- 🔑 **Account Management** - Export/import Gun pairs for account backup and recovery
|
|
13
|
-
- 📱 **Responsive Design** - Works seamlessly across all device sizes
|
|
14
|
-
- 🌍 **TypeScript Support** - Full type safety and IntelliSense support
|
|
15
|
-
- 🔌 **Plugin System** - Advanced Gun operations with custom hooks
|
|
16
|
-
- 📊 **Real-time Data** - Reactive data synchronization with RxJS observables
|
|
17
|
-
- ✅ **Robust Foundation** - Built on shogun-core v5.0.0 with 99.86% test coverage
|
|
18
|
-
- 🗄️ **Flexible Storage** - Support for GunDB, SQLite, PostgreSQL, MongoDB via TransportLayer
|
|
19
|
-
|
|
20
|
-
## 📦 Requirements
|
|
21
|
-
|
|
22
|
-
- **React**: ^18.0.0
|
|
23
|
-
- **shogun-core**: ^2.0.0
|
|
24
|
-
- **Node.js**: ≥18
|
|
25
|
-
|
|
26
|
-
## 🚀 Quick Start
|
|
27
|
-
|
|
28
|
-
### Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install shogun-button-react shogun-core
|
|
32
|
-
# or
|
|
33
|
-
yarn add shogun-button-react shogun-core
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Updating from 3.x
|
|
37
|
-
|
|
38
|
-
If you're upgrading from version 3.x:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
yarn upgrade shogun-button-react shogun-core
|
|
42
|
-
# or
|
|
43
|
-
npm update shogun-button-react shogun-core
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Basic Usage
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
import React from "react";
|
|
50
|
-
import { ShogunButton, ShogunButtonProvider, shogunConnector } from "shogun-button-react";
|
|
51
|
-
import "shogun-button-react/styles.css";
|
|
52
|
-
|
|
53
|
-
function App() {
|
|
54
|
-
const { core, options } = shogunConnector({
|
|
55
|
-
appName: "My Awesome App",
|
|
56
|
-
// Enable specific authentication methods
|
|
57
|
-
showMetamask: true,
|
|
58
|
-
showWebauthn: true,
|
|
59
|
-
showNostr: true,
|
|
60
|
-
showZkProof: true,
|
|
61
|
-
// Optional peers
|
|
62
|
-
peers: [
|
|
63
|
-
"https://gun-manhattan.herokuapp.com/gun"
|
|
64
|
-
],
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<ShogunButtonProvider
|
|
69
|
-
core={core}
|
|
70
|
-
options={options}
|
|
71
|
-
onLoginSuccess={(data) => {
|
|
72
|
-
console.log("Login successful!", data);
|
|
73
|
-
}}
|
|
74
|
-
onSignupSuccess={(data) => {
|
|
75
|
-
console.log("Account created successfully!", data);
|
|
76
|
-
}}
|
|
77
|
-
onError={(error) => {
|
|
78
|
-
console.error("Authentication error:", error);
|
|
79
|
-
}}
|
|
80
|
-
>
|
|
81
|
-
<div className="app">
|
|
82
|
-
<header>
|
|
83
|
-
<h1>Welcome to My Awesome App</h1>
|
|
84
|
-
<ShogunButton />
|
|
85
|
-
</header>
|
|
86
|
-
<main>{/* Your app content */}</main>
|
|
87
|
-
</div>
|
|
88
|
-
</ShogunButtonProvider>
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export default App;
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## 🔧 Advanced Configuration
|
|
96
|
-
|
|
97
|
-
### Custom Authentication Options
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
const { core, options } = shogunConnector({
|
|
101
|
-
appName: "My App",
|
|
102
|
-
|
|
103
|
-
// Toggle authentication methods in the UI
|
|
104
|
-
showMetamask: true,
|
|
105
|
-
showWebauthn: true,
|
|
106
|
-
showNostr: true,
|
|
107
|
-
showZkProof: true,
|
|
108
|
-
|
|
109
|
-
// Network configuration (backward compatible)
|
|
110
|
-
peers: [
|
|
111
|
-
"https://gun-manhattan.herokuapp.com/gun"
|
|
112
|
-
],
|
|
113
|
-
|
|
114
|
-
// ZK-Proof configuration
|
|
115
|
-
zkproof: {
|
|
116
|
-
enabled: true,
|
|
117
|
-
defaultGroupId: "my-app-users",
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
// Gun Advanced Plugin configuration
|
|
121
|
-
enableGunDebug: true,
|
|
122
|
-
enableConnectionMonitoring: true,
|
|
123
|
-
defaultPageSize: 20,
|
|
124
|
-
connectionTimeout: 10000,
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Advanced Transport Layer Configuration (New in v5.0.0)
|
|
129
|
-
|
|
130
|
-
```tsx
|
|
131
|
-
const { core, options } = shogunConnector({
|
|
132
|
-
appName: "My App",
|
|
133
|
-
|
|
134
|
-
// Use new transport layer system
|
|
135
|
-
transport: {
|
|
136
|
-
type: "gun", // or "sqlite", "postgresql", "mongodb", "custom"
|
|
137
|
-
options: {
|
|
138
|
-
peers: ["https://gun-manhattan.herokuapp.com/gun"],
|
|
139
|
-
// Additional transport-specific options
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
// Alternative: Use SQLite for local development
|
|
144
|
-
transport: {
|
|
145
|
-
type: "sqlite",
|
|
146
|
-
options: {
|
|
147
|
-
filename: "./my-app.db",
|
|
148
|
-
// SQLite-specific options
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
// Alternative: Use PostgreSQL for production
|
|
153
|
-
transport: {
|
|
154
|
-
type: "postgresql",
|
|
155
|
-
options: {
|
|
156
|
-
host: "localhost",
|
|
157
|
-
port: 5432,
|
|
158
|
-
database: "myapp",
|
|
159
|
-
username: "user",
|
|
160
|
-
password: "password",
|
|
161
|
-
// PostgreSQL-specific options
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
// Authentication methods
|
|
166
|
-
showMetamask: true,
|
|
167
|
-
showWebauthn: true,
|
|
168
|
-
showNostr: true,
|
|
169
|
-
showZkProof: true,
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## 🎯 API Reference
|
|
174
|
-
|
|
175
|
-
### ShogunButtonProvider
|
|
176
|
-
|
|
177
|
-
The provider component that supplies Shogun context to your application.
|
|
178
|
-
|
|
179
|
-
#### Props
|
|
180
|
-
|
|
181
|
-
| Name | Type | Description | Required |
|
|
182
|
-
|------|------|-------------|----------|
|
|
183
|
-
| `core` | `ShogunCore` | Shogun SDK instance created by `shogunConnector` | ✅ |
|
|
184
|
-
| `options` | `ShogunConnectorOptions` | Configuration options | ✅ |
|
|
185
|
-
| `onLoginSuccess` | `(data: AuthData) => void` | Callback fired on successful login | ❌ |
|
|
186
|
-
| `onSignupSuccess` | `(data: AuthData) => void` | Callback fired on successful signup | ❌ |
|
|
187
|
-
| `onError` | `(error: string) => void` | Callback fired when an error occurs | ❌ |
|
|
188
|
-
|
|
189
|
-
#### AuthData Interface
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
interface AuthData {
|
|
193
|
-
userPub: string; // User's public key
|
|
194
|
-
username: string; // Display name
|
|
195
|
-
password?: string; // Password (if applicable)
|
|
196
|
-
seedPhrase?: string; // Seed phrase/trapdoor (for ZK-Proof)
|
|
197
|
-
authMethod?: "password" | "web3" | "webauthn" | "nostr" | "zkproof" | "pair";
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### ShogunButton
|
|
202
|
-
|
|
203
|
-
The main button component that provides a complete authentication UI with modal dialogs for login, signup, and account management.
|
|
204
|
-
|
|
205
|
-
**Features:**
|
|
206
|
-
- Multi-method authentication selection
|
|
207
|
-
- Password-based login/signup with recovery
|
|
208
|
-
- Gun pair export/import for account backup
|
|
209
|
-
- Responsive modal design
|
|
210
|
-
- Error handling and user feedback
|
|
211
|
-
|
|
212
|
-
### useShogun Hook
|
|
213
|
-
|
|
214
|
-
A comprehensive hook to access Shogun authentication state and functions.
|
|
215
|
-
|
|
216
|
-
```tsx
|
|
217
|
-
import React, { useEffect } from "react";
|
|
218
|
-
import { useShogun } from "shogun-button-react";
|
|
219
|
-
|
|
220
|
-
function UserProfile() {
|
|
221
|
-
const {
|
|
222
|
-
// Authentication state
|
|
223
|
-
isLoggedIn,
|
|
224
|
-
userPub,
|
|
225
|
-
username,
|
|
226
|
-
|
|
227
|
-
// Authentication methods
|
|
228
|
-
login,
|
|
229
|
-
signUp,
|
|
230
|
-
logout,
|
|
231
|
-
|
|
232
|
-
// Plugin management
|
|
233
|
-
hasPlugin,
|
|
234
|
-
getPlugin,
|
|
235
|
-
|
|
236
|
-
// Account management
|
|
237
|
-
exportGunPair,
|
|
238
|
-
importGunPair,
|
|
239
|
-
|
|
240
|
-
// Data operations
|
|
241
|
-
observe,
|
|
242
|
-
put,
|
|
243
|
-
get,
|
|
244
|
-
remove,
|
|
245
|
-
|
|
246
|
-
// Advanced Gun hooks
|
|
247
|
-
useGunState,
|
|
248
|
-
useGunCollection,
|
|
249
|
-
useGunConnection,
|
|
250
|
-
useGunDebug,
|
|
251
|
-
useGunRealtime,
|
|
252
|
-
} = useShogun();
|
|
253
|
-
|
|
254
|
-
// Example: Login with different methods
|
|
255
|
-
const handlePasswordLogin = async () => {
|
|
256
|
-
try {
|
|
257
|
-
const result = await login("password", "username", "password");
|
|
258
|
-
if (result.success) {
|
|
259
|
-
console.log("Password login successful!");
|
|
260
|
-
}
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error("Login failed:", error);
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
const handleMetaMaskLogin = async () => {
|
|
267
|
-
try {
|
|
268
|
-
const result = await login("web3");
|
|
269
|
-
if (result.success) {
|
|
270
|
-
console.log("MetaMask login successful!");
|
|
271
|
-
}
|
|
272
|
-
} catch (error) {
|
|
273
|
-
console.error("MetaMask login failed:", error);
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
const handleWebAuthnLogin = async () => {
|
|
278
|
-
try {
|
|
279
|
-
const result = await login("webauthn", "username");
|
|
280
|
-
if (result.success) {
|
|
281
|
-
console.log("WebAuthn login successful!");
|
|
282
|
-
}
|
|
283
|
-
} catch (error) {
|
|
284
|
-
console.error("WebAuthn login failed:", error);
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const handleZkProofSignup = async () => {
|
|
289
|
-
try {
|
|
290
|
-
const result = await signUp("zkproof");
|
|
291
|
-
if (result.success && result.seedPhrase) {
|
|
292
|
-
console.log("ZK-Proof signup successful!");
|
|
293
|
-
console.log("SAVE THIS TRAPDOOR:", result.seedPhrase);
|
|
294
|
-
// CRITICAL: User must save the trapdoor for account recovery
|
|
295
|
-
}
|
|
296
|
-
} catch (error) {
|
|
297
|
-
console.error("ZK-Proof signup failed:", error);
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
const handleZkProofLogin = async () => {
|
|
302
|
-
try {
|
|
303
|
-
const trapdoor = "user-saved-trapdoor-here";
|
|
304
|
-
const result = await login("zkproof", trapdoor);
|
|
305
|
-
if (result.success) {
|
|
306
|
-
console.log("ZK-Proof anonymous login successful!");
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
console.error("ZK-Proof login failed:", error);
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
// Example: Account backup and recovery
|
|
314
|
-
const handleExportAccount = async () => {
|
|
315
|
-
try {
|
|
316
|
-
const pairData = await exportGunPair("my-secure-password");
|
|
317
|
-
console.log("Account exported successfully!");
|
|
318
|
-
|
|
319
|
-
// Save to file or copy to clipboard
|
|
320
|
-
if (navigator.clipboard) {
|
|
321
|
-
await navigator.clipboard.writeText(pairData);
|
|
322
|
-
alert("Account data copied to clipboard!");
|
|
323
|
-
}
|
|
324
|
-
} catch (error) {
|
|
325
|
-
console.error("Export failed:", error);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
const handleImportAccount = async (pairData: string, password?: string) => {
|
|
330
|
-
try {
|
|
331
|
-
const success = await importGunPair(pairData, password);
|
|
332
|
-
if (success) {
|
|
333
|
-
console.log("Account imported successfully!");
|
|
334
|
-
}
|
|
335
|
-
} catch (error) {
|
|
336
|
-
console.error("Import failed:", error);
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
// Example: Real-time data observation
|
|
341
|
-
useEffect(() => {
|
|
342
|
-
if (isLoggedIn) {
|
|
343
|
-
const subscription = observe<any>('user/profile').subscribe(data => {
|
|
344
|
-
console.log('Profile updated:', data);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
return () => subscription.unsubscribe();
|
|
348
|
-
}
|
|
349
|
-
}, [isLoggedIn, observe]);
|
|
350
|
-
|
|
351
|
-
if (!isLoggedIn) {
|
|
352
|
-
return <div>Please log in to view your profile</div>;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return (
|
|
356
|
-
<div className="user-profile">
|
|
357
|
-
<h2>Welcome, {username}!</h2>
|
|
358
|
-
<div className="profile-info">
|
|
359
|
-
<p><strong>Public Key:</strong> {userPub}</p>
|
|
360
|
-
<p><strong>Authentication Method:</strong> {authMethod}</p>
|
|
361
|
-
</div>
|
|
362
|
-
|
|
363
|
-
<div className="actions">
|
|
364
|
-
<button onClick={handleExportAccount}>Export Account</button>
|
|
365
|
-
<button onClick={logout}>Logout</button>
|
|
366
|
-
</div>
|
|
367
|
-
</div>
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
## 🔌 Advanced Gun Plugin Usage
|
|
373
|
-
|
|
374
|
-
### Using Gun State Hooks
|
|
375
|
-
|
|
376
|
-
```tsx
|
|
377
|
-
function UserSettings() {
|
|
378
|
-
const { useGunState, useGunCollection } = useShogun();
|
|
379
|
-
|
|
380
|
-
// Single value state
|
|
381
|
-
const profile = useGunState('user/profile', {
|
|
382
|
-
name: '',
|
|
383
|
-
email: '',
|
|
384
|
-
preferences: {}
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Collection management
|
|
388
|
-
const posts = useGunCollection('user/posts', {
|
|
389
|
-
pageSize: 10,
|
|
390
|
-
sortBy: 'createdAt',
|
|
391
|
-
sortOrder: 'desc',
|
|
392
|
-
filter: (post) => post.isPublished
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
const updateProfile = async () => {
|
|
396
|
-
await profile.update({
|
|
397
|
-
name: 'New Name',
|
|
398
|
-
preferences: { theme: 'dark' }
|
|
399
|
-
});
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
const addPost = async () => {
|
|
403
|
-
await posts.addItem({
|
|
404
|
-
title: 'New Post',
|
|
405
|
-
content: 'Post content...',
|
|
406
|
-
createdAt: Date.now(),
|
|
407
|
-
isPublished: true
|
|
408
|
-
});
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
return (
|
|
412
|
-
<div>
|
|
413
|
-
<h3>Profile Settings</h3>
|
|
414
|
-
{profile.isLoading ? (
|
|
415
|
-
<p>Loading...</p>
|
|
416
|
-
) : profile.error ? (
|
|
417
|
-
<p>Error: {profile.error}</p>
|
|
418
|
-
) : (
|
|
419
|
-
<div>
|
|
420
|
-
<input
|
|
421
|
-
value={profile.data?.name || ''}
|
|
422
|
-
onChange={(e) => profile.update({ name: e.target.value })}
|
|
423
|
-
placeholder="Name"
|
|
424
|
-
/>
|
|
425
|
-
<button onClick={updateProfile}>Save Changes</button>
|
|
426
|
-
</div>
|
|
427
|
-
)}
|
|
428
|
-
|
|
429
|
-
<h3>Your Posts ({posts.items.length})</h3>
|
|
430
|
-
{posts.isLoading ? (
|
|
431
|
-
<p>Loading posts...</p>
|
|
432
|
-
) : (
|
|
433
|
-
<div>
|
|
434
|
-
{posts.items.map((post, index) => (
|
|
435
|
-
<div key={index}>
|
|
436
|
-
<h4>{post.title}</h4>
|
|
437
|
-
<p>{post.content}</p>
|
|
438
|
-
</div>
|
|
439
|
-
))}
|
|
440
|
-
|
|
441
|
-
<div className="pagination">
|
|
442
|
-
{posts.hasPrevPage && (
|
|
443
|
-
<button onClick={posts.prevPage}>Previous</button>
|
|
444
|
-
)}
|
|
445
|
-
<span>Page {posts.currentPage + 1} of {posts.totalPages}</span>
|
|
446
|
-
{posts.hasNextPage && (
|
|
447
|
-
<button onClick={posts.nextPage}>Next</button>
|
|
448
|
-
)}
|
|
449
|
-
</div>
|
|
450
|
-
</div>
|
|
451
|
-
)}
|
|
452
|
-
</div>
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### ZK-Proof Anonymous Authentication
|
|
458
|
-
|
|
459
|
-
ZK-Proof (Zero-Knowledge Proof) authentication provides complete anonymity using Semaphore protocol. Users can authenticate without revealing their identity.
|
|
460
|
-
|
|
461
|
-
```tsx
|
|
462
|
-
function ZkProofExample() {
|
|
463
|
-
const { login, signUp } = useShogun();
|
|
464
|
-
const [trapdoor, setTrapdoor] = useState("");
|
|
465
|
-
|
|
466
|
-
// Signup: Creates anonymous identity and returns trapdoor
|
|
467
|
-
const handleSignup = async () => {
|
|
468
|
-
try {
|
|
469
|
-
const result = await signUp("zkproof");
|
|
470
|
-
|
|
471
|
-
if (result.success && result.seedPhrase) {
|
|
472
|
-
// CRITICAL: User MUST save this trapdoor!
|
|
473
|
-
// It's the ONLY way to recover the anonymous account
|
|
474
|
-
console.log("Your trapdoor (save securely):", result.seedPhrase);
|
|
475
|
-
|
|
476
|
-
// Recommend user to:
|
|
477
|
-
// 1. Write it down on paper
|
|
478
|
-
// 2. Store in password manager
|
|
479
|
-
// 3. Keep multiple secure copies
|
|
480
|
-
alert(`Save this trapdoor securely:\n\n${result.seedPhrase}\n\nYou'll need it to login on other devices!`);
|
|
481
|
-
}
|
|
482
|
-
} catch (error) {
|
|
483
|
-
console.error("ZK-Proof signup failed:", error);
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
// Login: Use saved trapdoor to restore anonymous identity
|
|
488
|
-
const handleLogin = async () => {
|
|
489
|
-
try {
|
|
490
|
-
const result = await login("zkproof", trapdoor);
|
|
491
|
-
|
|
492
|
-
if (result.success) {
|
|
493
|
-
console.log("Logged in anonymously!");
|
|
494
|
-
console.log("Identity commitment:", result.userPub);
|
|
495
|
-
}
|
|
496
|
-
} catch (error) {
|
|
497
|
-
console.error("ZK-Proof login failed:", error);
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
return (
|
|
502
|
-
<div>
|
|
503
|
-
<h3>Anonymous Authentication with ZK-Proof</h3>
|
|
504
|
-
|
|
505
|
-
<div>
|
|
506
|
-
<button onClick={handleSignup}>
|
|
507
|
-
Create Anonymous Identity
|
|
508
|
-
</button>
|
|
509
|
-
</div>
|
|
510
|
-
|
|
511
|
-
<div>
|
|
512
|
-
<input
|
|
513
|
-
type="text"
|
|
514
|
-
value={trapdoor}
|
|
515
|
-
onChange={(e) => setTrapdoor(e.target.value)}
|
|
516
|
-
placeholder="Enter your trapdoor to login"
|
|
517
|
-
/>
|
|
518
|
-
<button onClick={handleLogin}>
|
|
519
|
-
Login Anonymously
|
|
520
|
-
</button>
|
|
521
|
-
</div>
|
|
522
|
-
</div>
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
**Important Notes about ZK-Proof:**
|
|
528
|
-
|
|
529
|
-
- **Trapdoor is Critical**: The trapdoor is like a master password - without it, the account is permanently lost
|
|
530
|
-
- **No Recovery**: Unlike traditional auth, there's no "forgot password" - trapdoor loss means permanent account loss
|
|
531
|
-
- **Complete Anonymity**: Your identity remains private even from the application
|
|
532
|
-
- **Multi-Device Support**: Use the same trapdoor on different devices
|
|
533
|
-
- **Privacy-Preserving**: Uses Semaphore protocol for zero-knowledge proofs
|
|
534
|
-
|
|
535
|
-
### Connection Monitoring
|
|
536
|
-
|
|
537
|
-
```tsx
|
|
538
|
-
function ConnectionStatus() {
|
|
539
|
-
const { useGunConnection, useGunDebug } = useShogun();
|
|
540
|
-
|
|
541
|
-
// Monitor connection status
|
|
542
|
-
const connection = useGunConnection('user/data');
|
|
543
|
-
|
|
544
|
-
// Enable debug logging
|
|
545
|
-
useGunDebug('user/data', true);
|
|
546
|
-
|
|
547
|
-
return (
|
|
548
|
-
<div className="connection-status">
|
|
549
|
-
<div className={`status-indicator ${connection.isConnected ? 'connected' : 'disconnected'}`}>
|
|
550
|
-
{connection.isConnected ? '🟢 Connected' : '🔴 Disconnected'}
|
|
551
|
-
</div>
|
|
552
|
-
|
|
553
|
-
{connection.lastSeen && (
|
|
554
|
-
<p>Last seen: {connection.lastSeen.toLocaleTimeString()}</p>
|
|
555
|
-
)}
|
|
556
|
-
|
|
557
|
-
{connection.error && (
|
|
558
|
-
<p className="error">Error: {connection.error}</p>
|
|
559
|
-
)}
|
|
560
|
-
</div>
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
## 🎨 Customization
|
|
566
|
-
|
|
567
|
-
### CSS Variables
|
|
568
|
-
|
|
569
|
-
Customize the appearance using CSS variables:
|
|
570
|
-
|
|
571
|
-
```css
|
|
572
|
-
:root {
|
|
573
|
-
/* Primary colors */
|
|
574
|
-
--shogun-primary: #3b82f6;
|
|
575
|
-
--shogun-primary-hover: #2563eb;
|
|
576
|
-
|
|
577
|
-
/* Background colors */
|
|
578
|
-
--shogun-bg: #ffffff;
|
|
579
|
-
--shogun-bg-secondary: #f3f4f6;
|
|
580
|
-
|
|
581
|
-
/* Text colors */
|
|
582
|
-
--shogun-text: #1f2937;
|
|
583
|
-
--shogun-text-secondary: #6b7280;
|
|
584
|
-
|
|
585
|
-
/* Border and shadow */
|
|
586
|
-
--shogun-border: #e5e7eb;
|
|
587
|
-
--shogun-border-radius: 12px;
|
|
588
|
-
--shogun-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
589
|
-
|
|
590
|
-
/* Transitions */
|
|
591
|
-
--shogun-transition: all 0.2s ease;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/* Dark mode overrides */
|
|
595
|
-
@media (prefers-color-scheme: dark) {
|
|
596
|
-
:root {
|
|
597
|
-
--shogun-bg: #1f2937;
|
|
598
|
-
--shogun-bg-secondary: #374151;
|
|
599
|
-
--shogun-text: #f3f4f6;
|
|
600
|
-
--shogun-text-secondary: #9ca3af;
|
|
601
|
-
--shogun-border: #4b5563;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
### Custom Styling
|
|
607
|
-
|
|
608
|
-
```css
|
|
609
|
-
/* Custom button styles */
|
|
610
|
-
.shogun-connect-button {
|
|
611
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
612
|
-
border-radius: 25px;
|
|
613
|
-
font-weight: 700;
|
|
614
|
-
text-transform: uppercase;
|
|
615
|
-
letter-spacing: 1px;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/* Custom modal styles */
|
|
619
|
-
.shogun-modal {
|
|
620
|
-
border-radius: 20px;
|
|
621
|
-
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
/* Custom form styles */
|
|
625
|
-
.shogun-form-group input {
|
|
626
|
-
border-radius: 10px;
|
|
627
|
-
border: 2px solid transparent;
|
|
628
|
-
transition: border-color 0.3s ease;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
.shogun-form-group input:focus {
|
|
632
|
-
border-color: var(--shogun-primary);
|
|
633
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
634
|
-
}
|
|
635
|
-
```
|
|
636
|
-
|
|
637
|
-
## 🔧 Configuration Options
|
|
638
|
-
|
|
639
|
-
### Complete Configuration Interface
|
|
640
|
-
|
|
641
|
-
```typescript
|
|
642
|
-
interface ShogunConnectorOptions {
|
|
643
|
-
// App information
|
|
644
|
-
appName: string;
|
|
645
|
-
|
|
646
|
-
// Feature toggles
|
|
647
|
-
showMetamask?: boolean;
|
|
648
|
-
showWebauthn?: boolean;
|
|
649
|
-
showNostr?: boolean;
|
|
650
|
-
darkMode?: boolean;
|
|
651
|
-
|
|
652
|
-
// Network configuration (backward compatible)
|
|
653
|
-
peers?: string[];
|
|
654
|
-
authToken?: string;
|
|
655
|
-
gunInstance?: IGunInstance<any>;
|
|
656
|
-
gunOptions?: any;
|
|
657
|
-
|
|
658
|
-
// Transport layer configuration (new in v5.0.0)
|
|
659
|
-
transport?: {
|
|
660
|
-
type: "gun" | "sqlite" | "postgresql" | "mongodb" | "custom";
|
|
661
|
-
options?: any;
|
|
662
|
-
customTransport?: any;
|
|
663
|
-
};
|
|
664
|
-
|
|
665
|
-
// Timeouts and provider configs
|
|
666
|
-
timeouts?: {
|
|
667
|
-
login?: number;
|
|
668
|
-
signup?: number;
|
|
669
|
-
operation?: number;
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
// Gun Advanced Plugin configuration
|
|
673
|
-
enableGunDebug?: boolean;
|
|
674
|
-
enableConnectionMonitoring?: boolean;
|
|
675
|
-
defaultPageSize?: number;
|
|
676
|
-
connectionTimeout?: number;
|
|
677
|
-
debounceInterval?: number;
|
|
678
|
-
}
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
### Connector Result
|
|
682
|
-
|
|
683
|
-
```typescript
|
|
684
|
-
interface ShogunConnectorResult {
|
|
685
|
-
core: ShogunCore;
|
|
686
|
-
options: ShogunConnectorOptions;
|
|
687
|
-
setProvider: (provider: any) => boolean;
|
|
688
|
-
getCurrentProviderUrl: () => string | null;
|
|
689
|
-
registerPlugin: (plugin: any) => boolean;
|
|
690
|
-
hasPlugin: (name: string) => boolean;
|
|
691
|
-
gunPlugin: null;
|
|
692
|
-
}
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
## 🌐 Browser Support
|
|
696
|
-
|
|
697
|
-
- **Chrome** ≥ 60
|
|
698
|
-
- **Firefox** ≥ 60
|
|
699
|
-
- **Safari** ≥ 12
|
|
700
|
-
- **Edge** ≥ 79
|
|
701
|
-
|
|
702
|
-
## 📱 Mobile Support
|
|
703
|
-
|
|
704
|
-
The library is fully responsive and works seamlessly on mobile devices. All authentication methods are optimized for touch interfaces.
|
|
705
|
-
|
|
706
|
-
## 🔒 Security Features
|
|
707
|
-
|
|
708
|
-
- **Encrypted Storage**: Gun pairs can be encrypted with passwords
|
|
709
|
-
- **Secure Authentication**: Multiple secure authentication methods
|
|
710
|
-
- **Session Management**: Automatic session handling and cleanup
|
|
711
|
-
- **Error Handling**: Comprehensive error handling and user feedback
|
|
712
|
-
|
|
713
|
-
## 🚀 Performance
|
|
714
|
-
|
|
715
|
-
- **Lazy Loading**: Components load only when needed
|
|
716
|
-
- **Optimized Rendering**: Efficient React rendering with proper memoization
|
|
717
|
-
- **Connection Pooling**: Smart connection management for optimal performance
|
|
718
|
-
- **Debounced Updates**: Prevents excessive re-renders during rapid data changes
|
|
719
|
-
|
|
720
|
-
## 🤝 Contributing
|
|
721
|
-
|
|
722
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
723
|
-
|
|
724
|
-
### Development Setup
|
|
725
|
-
|
|
726
|
-
```bash
|
|
727
|
-
# Clone the repository
|
|
728
|
-
git clone https://github.com/shogun/shogun-button-react.git
|
|
729
|
-
|
|
730
|
-
# Install dependencies
|
|
731
|
-
yarn install
|
|
732
|
-
|
|
733
|
-
# Start development server
|
|
734
|
-
yarn dev
|
|
735
|
-
|
|
736
|
-
# Build the library
|
|
737
|
-
yarn build
|
|
738
|
-
|
|
739
|
-
# Run tests
|
|
740
|
-
yarn test
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
## 📄 License
|
|
744
|
-
|
|
745
|
-
MIT © [Shogun](https://github.com/shogun)
|
|
746
|
-
|
|
747
|
-
## 🆘 Support
|
|
748
|
-
|
|
749
|
-
- **Documentation**: [Full API Reference](https://docs.shogun.dev)
|
|
750
|
-
- **Issues**: [GitHub Issues](https://github.com/shogun/shogun-button-react/issues)
|
|
751
|
-
- **Discussions**: [GitHub Discussions](https://github.com/shogun/shogun-button-react/discussions)
|
|
752
|
-
- **Discord**: [Join our community](https://discord.gg/shogun)
|
|
1
|
+
# Shogun Button React
|
|
2
|
+
|
|
3
|
+
A comprehensive React component library for seamless integration of Shogun authentication into your applications. This library provides a simple yet powerful way to add multi-method authentication, account management, and real-time data synchronization to your React applications.
|
|
4
|
+
|
|
5
|
+
> **Version 5.0.0** - Compatible with shogun-core ^2.0.0
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- 🚀 **Easy Integration** - Simple setup with minimal configuration
|
|
10
|
+
- 🎨 **Customizable UI** - Modern, responsive design with dark mode support
|
|
11
|
+
- 🔒 **Multi-Authentication** - Support for Password, MetaMask, WebAuthn, Nostr, and ZK-Proof
|
|
12
|
+
- 🔑 **Account Management** - Export/import Gun pairs for account backup and recovery
|
|
13
|
+
- 📱 **Responsive Design** - Works seamlessly across all device sizes
|
|
14
|
+
- 🌍 **TypeScript Support** - Full type safety and IntelliSense support
|
|
15
|
+
- 🔌 **Plugin System** - Advanced Gun operations with custom hooks
|
|
16
|
+
- 📊 **Real-time Data** - Reactive data synchronization with RxJS observables
|
|
17
|
+
- ✅ **Robust Foundation** - Built on shogun-core v5.0.0 with 99.86% test coverage
|
|
18
|
+
- 🗄️ **Flexible Storage** - Support for GunDB, SQLite, PostgreSQL, MongoDB via TransportLayer
|
|
19
|
+
|
|
20
|
+
## 📦 Requirements
|
|
21
|
+
|
|
22
|
+
- **React**: ^18.0.0
|
|
23
|
+
- **shogun-core**: ^2.0.0
|
|
24
|
+
- **Node.js**: ≥18
|
|
25
|
+
|
|
26
|
+
## 🚀 Quick Start
|
|
27
|
+
|
|
28
|
+
### Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install shogun-button-react shogun-core
|
|
32
|
+
# or
|
|
33
|
+
yarn add shogun-button-react shogun-core
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Updating from 3.x
|
|
37
|
+
|
|
38
|
+
If you're upgrading from version 3.x:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
yarn upgrade shogun-button-react shogun-core
|
|
42
|
+
# or
|
|
43
|
+
npm update shogun-button-react shogun-core
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Basic Usage
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import React from "react";
|
|
50
|
+
import { ShogunButton, ShogunButtonProvider, shogunConnector } from "shogun-button-react";
|
|
51
|
+
import "shogun-button-react/styles.css";
|
|
52
|
+
|
|
53
|
+
function App() {
|
|
54
|
+
const { core, options } = shogunConnector({
|
|
55
|
+
appName: "My Awesome App",
|
|
56
|
+
// Enable specific authentication methods
|
|
57
|
+
showMetamask: true,
|
|
58
|
+
showWebauthn: true,
|
|
59
|
+
showNostr: true,
|
|
60
|
+
showZkProof: true,
|
|
61
|
+
// Optional peers
|
|
62
|
+
peers: [
|
|
63
|
+
"https://gun-manhattan.herokuapp.com/gun"
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<ShogunButtonProvider
|
|
69
|
+
core={core}
|
|
70
|
+
options={options}
|
|
71
|
+
onLoginSuccess={(data) => {
|
|
72
|
+
console.log("Login successful!", data);
|
|
73
|
+
}}
|
|
74
|
+
onSignupSuccess={(data) => {
|
|
75
|
+
console.log("Account created successfully!", data);
|
|
76
|
+
}}
|
|
77
|
+
onError={(error) => {
|
|
78
|
+
console.error("Authentication error:", error);
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<div className="app">
|
|
82
|
+
<header>
|
|
83
|
+
<h1>Welcome to My Awesome App</h1>
|
|
84
|
+
<ShogunButton />
|
|
85
|
+
</header>
|
|
86
|
+
<main>{/* Your app content */}</main>
|
|
87
|
+
</div>
|
|
88
|
+
</ShogunButtonProvider>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default App;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 🔧 Advanced Configuration
|
|
96
|
+
|
|
97
|
+
### Custom Authentication Options
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
const { core, options } = shogunConnector({
|
|
101
|
+
appName: "My App",
|
|
102
|
+
|
|
103
|
+
// Toggle authentication methods in the UI
|
|
104
|
+
showMetamask: true,
|
|
105
|
+
showWebauthn: true,
|
|
106
|
+
showNostr: true,
|
|
107
|
+
showZkProof: true,
|
|
108
|
+
|
|
109
|
+
// Network configuration (backward compatible)
|
|
110
|
+
peers: [
|
|
111
|
+
"https://gun-manhattan.herokuapp.com/gun"
|
|
112
|
+
],
|
|
113
|
+
|
|
114
|
+
// ZK-Proof configuration
|
|
115
|
+
zkproof: {
|
|
116
|
+
enabled: true,
|
|
117
|
+
defaultGroupId: "my-app-users",
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// Gun Advanced Plugin configuration
|
|
121
|
+
enableGunDebug: true,
|
|
122
|
+
enableConnectionMonitoring: true,
|
|
123
|
+
defaultPageSize: 20,
|
|
124
|
+
connectionTimeout: 10000,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Advanced Transport Layer Configuration (New in v5.0.0)
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
const { core, options } = shogunConnector({
|
|
132
|
+
appName: "My App",
|
|
133
|
+
|
|
134
|
+
// Use new transport layer system
|
|
135
|
+
transport: {
|
|
136
|
+
type: "gun", // or "sqlite", "postgresql", "mongodb", "custom"
|
|
137
|
+
options: {
|
|
138
|
+
peers: ["https://gun-manhattan.herokuapp.com/gun"],
|
|
139
|
+
// Additional transport-specific options
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Alternative: Use SQLite for local development
|
|
144
|
+
transport: {
|
|
145
|
+
type: "sqlite",
|
|
146
|
+
options: {
|
|
147
|
+
filename: "./my-app.db",
|
|
148
|
+
// SQLite-specific options
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// Alternative: Use PostgreSQL for production
|
|
153
|
+
transport: {
|
|
154
|
+
type: "postgresql",
|
|
155
|
+
options: {
|
|
156
|
+
host: "localhost",
|
|
157
|
+
port: 5432,
|
|
158
|
+
database: "myapp",
|
|
159
|
+
username: "user",
|
|
160
|
+
password: "password",
|
|
161
|
+
// PostgreSQL-specific options
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// Authentication methods
|
|
166
|
+
showMetamask: true,
|
|
167
|
+
showWebauthn: true,
|
|
168
|
+
showNostr: true,
|
|
169
|
+
showZkProof: true,
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 🎯 API Reference
|
|
174
|
+
|
|
175
|
+
### ShogunButtonProvider
|
|
176
|
+
|
|
177
|
+
The provider component that supplies Shogun context to your application.
|
|
178
|
+
|
|
179
|
+
#### Props
|
|
180
|
+
|
|
181
|
+
| Name | Type | Description | Required |
|
|
182
|
+
|------|------|-------------|----------|
|
|
183
|
+
| `core` | `ShogunCore` | Shogun SDK instance created by `shogunConnector` | ✅ |
|
|
184
|
+
| `options` | `ShogunConnectorOptions` | Configuration options | ✅ |
|
|
185
|
+
| `onLoginSuccess` | `(data: AuthData) => void` | Callback fired on successful login | ❌ |
|
|
186
|
+
| `onSignupSuccess` | `(data: AuthData) => void` | Callback fired on successful signup | ❌ |
|
|
187
|
+
| `onError` | `(error: string) => void` | Callback fired when an error occurs | ❌ |
|
|
188
|
+
|
|
189
|
+
#### AuthData Interface
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
interface AuthData {
|
|
193
|
+
userPub: string; // User's public key
|
|
194
|
+
username: string; // Display name
|
|
195
|
+
password?: string; // Password (if applicable)
|
|
196
|
+
seedPhrase?: string; // Seed phrase/trapdoor (for ZK-Proof)
|
|
197
|
+
authMethod?: "password" | "web3" | "webauthn" | "nostr" | "zkproof" | "pair";
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### ShogunButton
|
|
202
|
+
|
|
203
|
+
The main button component that provides a complete authentication UI with modal dialogs for login, signup, and account management.
|
|
204
|
+
|
|
205
|
+
**Features:**
|
|
206
|
+
- Multi-method authentication selection
|
|
207
|
+
- Password-based login/signup with recovery
|
|
208
|
+
- Gun pair export/import for account backup
|
|
209
|
+
- Responsive modal design
|
|
210
|
+
- Error handling and user feedback
|
|
211
|
+
|
|
212
|
+
### useShogun Hook
|
|
213
|
+
|
|
214
|
+
A comprehensive hook to access Shogun authentication state and functions.
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import React, { useEffect } from "react";
|
|
218
|
+
import { useShogun } from "shogun-button-react";
|
|
219
|
+
|
|
220
|
+
function UserProfile() {
|
|
221
|
+
const {
|
|
222
|
+
// Authentication state
|
|
223
|
+
isLoggedIn,
|
|
224
|
+
userPub,
|
|
225
|
+
username,
|
|
226
|
+
|
|
227
|
+
// Authentication methods
|
|
228
|
+
login,
|
|
229
|
+
signUp,
|
|
230
|
+
logout,
|
|
231
|
+
|
|
232
|
+
// Plugin management
|
|
233
|
+
hasPlugin,
|
|
234
|
+
getPlugin,
|
|
235
|
+
|
|
236
|
+
// Account management
|
|
237
|
+
exportGunPair,
|
|
238
|
+
importGunPair,
|
|
239
|
+
|
|
240
|
+
// Data operations
|
|
241
|
+
observe,
|
|
242
|
+
put,
|
|
243
|
+
get,
|
|
244
|
+
remove,
|
|
245
|
+
|
|
246
|
+
// Advanced Gun hooks
|
|
247
|
+
useGunState,
|
|
248
|
+
useGunCollection,
|
|
249
|
+
useGunConnection,
|
|
250
|
+
useGunDebug,
|
|
251
|
+
useGunRealtime,
|
|
252
|
+
} = useShogun();
|
|
253
|
+
|
|
254
|
+
// Example: Login with different methods
|
|
255
|
+
const handlePasswordLogin = async () => {
|
|
256
|
+
try {
|
|
257
|
+
const result = await login("password", "username", "password");
|
|
258
|
+
if (result.success) {
|
|
259
|
+
console.log("Password login successful!");
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error("Login failed:", error);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const handleMetaMaskLogin = async () => {
|
|
267
|
+
try {
|
|
268
|
+
const result = await login("web3");
|
|
269
|
+
if (result.success) {
|
|
270
|
+
console.log("MetaMask login successful!");
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error("MetaMask login failed:", error);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const handleWebAuthnLogin = async () => {
|
|
278
|
+
try {
|
|
279
|
+
const result = await login("webauthn", "username");
|
|
280
|
+
if (result.success) {
|
|
281
|
+
console.log("WebAuthn login successful!");
|
|
282
|
+
}
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.error("WebAuthn login failed:", error);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const handleZkProofSignup = async () => {
|
|
289
|
+
try {
|
|
290
|
+
const result = await signUp("zkproof");
|
|
291
|
+
if (result.success && result.seedPhrase) {
|
|
292
|
+
console.log("ZK-Proof signup successful!");
|
|
293
|
+
console.log("SAVE THIS TRAPDOOR:", result.seedPhrase);
|
|
294
|
+
// CRITICAL: User must save the trapdoor for account recovery
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error("ZK-Proof signup failed:", error);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const handleZkProofLogin = async () => {
|
|
302
|
+
try {
|
|
303
|
+
const trapdoor = "user-saved-trapdoor-here";
|
|
304
|
+
const result = await login("zkproof", trapdoor);
|
|
305
|
+
if (result.success) {
|
|
306
|
+
console.log("ZK-Proof anonymous login successful!");
|
|
307
|
+
}
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error("ZK-Proof login failed:", error);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// Example: Account backup and recovery
|
|
314
|
+
const handleExportAccount = async () => {
|
|
315
|
+
try {
|
|
316
|
+
const pairData = await exportGunPair("my-secure-password");
|
|
317
|
+
console.log("Account exported successfully!");
|
|
318
|
+
|
|
319
|
+
// Save to file or copy to clipboard
|
|
320
|
+
if (navigator.clipboard) {
|
|
321
|
+
await navigator.clipboard.writeText(pairData);
|
|
322
|
+
alert("Account data copied to clipboard!");
|
|
323
|
+
}
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error("Export failed:", error);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const handleImportAccount = async (pairData: string, password?: string) => {
|
|
330
|
+
try {
|
|
331
|
+
const success = await importGunPair(pairData, password);
|
|
332
|
+
if (success) {
|
|
333
|
+
console.log("Account imported successfully!");
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error("Import failed:", error);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// Example: Real-time data observation
|
|
341
|
+
useEffect(() => {
|
|
342
|
+
if (isLoggedIn) {
|
|
343
|
+
const subscription = observe<any>('user/profile').subscribe(data => {
|
|
344
|
+
console.log('Profile updated:', data);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
return () => subscription.unsubscribe();
|
|
348
|
+
}
|
|
349
|
+
}, [isLoggedIn, observe]);
|
|
350
|
+
|
|
351
|
+
if (!isLoggedIn) {
|
|
352
|
+
return <div>Please log in to view your profile</div>;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div className="user-profile">
|
|
357
|
+
<h2>Welcome, {username}!</h2>
|
|
358
|
+
<div className="profile-info">
|
|
359
|
+
<p><strong>Public Key:</strong> {userPub}</p>
|
|
360
|
+
<p><strong>Authentication Method:</strong> {authMethod}</p>
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
<div className="actions">
|
|
364
|
+
<button onClick={handleExportAccount}>Export Account</button>
|
|
365
|
+
<button onClick={logout}>Logout</button>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 🔌 Advanced Gun Plugin Usage
|
|
373
|
+
|
|
374
|
+
### Using Gun State Hooks
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
function UserSettings() {
|
|
378
|
+
const { useGunState, useGunCollection } = useShogun();
|
|
379
|
+
|
|
380
|
+
// Single value state
|
|
381
|
+
const profile = useGunState('user/profile', {
|
|
382
|
+
name: '',
|
|
383
|
+
email: '',
|
|
384
|
+
preferences: {}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Collection management
|
|
388
|
+
const posts = useGunCollection('user/posts', {
|
|
389
|
+
pageSize: 10,
|
|
390
|
+
sortBy: 'createdAt',
|
|
391
|
+
sortOrder: 'desc',
|
|
392
|
+
filter: (post) => post.isPublished
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const updateProfile = async () => {
|
|
396
|
+
await profile.update({
|
|
397
|
+
name: 'New Name',
|
|
398
|
+
preferences: { theme: 'dark' }
|
|
399
|
+
});
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const addPost = async () => {
|
|
403
|
+
await posts.addItem({
|
|
404
|
+
title: 'New Post',
|
|
405
|
+
content: 'Post content...',
|
|
406
|
+
createdAt: Date.now(),
|
|
407
|
+
isPublished: true
|
|
408
|
+
});
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
<div>
|
|
413
|
+
<h3>Profile Settings</h3>
|
|
414
|
+
{profile.isLoading ? (
|
|
415
|
+
<p>Loading...</p>
|
|
416
|
+
) : profile.error ? (
|
|
417
|
+
<p>Error: {profile.error}</p>
|
|
418
|
+
) : (
|
|
419
|
+
<div>
|
|
420
|
+
<input
|
|
421
|
+
value={profile.data?.name || ''}
|
|
422
|
+
onChange={(e) => profile.update({ name: e.target.value })}
|
|
423
|
+
placeholder="Name"
|
|
424
|
+
/>
|
|
425
|
+
<button onClick={updateProfile}>Save Changes</button>
|
|
426
|
+
</div>
|
|
427
|
+
)}
|
|
428
|
+
|
|
429
|
+
<h3>Your Posts ({posts.items.length})</h3>
|
|
430
|
+
{posts.isLoading ? (
|
|
431
|
+
<p>Loading posts...</p>
|
|
432
|
+
) : (
|
|
433
|
+
<div>
|
|
434
|
+
{posts.items.map((post, index) => (
|
|
435
|
+
<div key={index}>
|
|
436
|
+
<h4>{post.title}</h4>
|
|
437
|
+
<p>{post.content}</p>
|
|
438
|
+
</div>
|
|
439
|
+
))}
|
|
440
|
+
|
|
441
|
+
<div className="pagination">
|
|
442
|
+
{posts.hasPrevPage && (
|
|
443
|
+
<button onClick={posts.prevPage}>Previous</button>
|
|
444
|
+
)}
|
|
445
|
+
<span>Page {posts.currentPage + 1} of {posts.totalPages}</span>
|
|
446
|
+
{posts.hasNextPage && (
|
|
447
|
+
<button onClick={posts.nextPage}>Next</button>
|
|
448
|
+
)}
|
|
449
|
+
</div>
|
|
450
|
+
</div>
|
|
451
|
+
)}
|
|
452
|
+
</div>
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### ZK-Proof Anonymous Authentication
|
|
458
|
+
|
|
459
|
+
ZK-Proof (Zero-Knowledge Proof) authentication provides complete anonymity using Semaphore protocol. Users can authenticate without revealing their identity.
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
function ZkProofExample() {
|
|
463
|
+
const { login, signUp } = useShogun();
|
|
464
|
+
const [trapdoor, setTrapdoor] = useState("");
|
|
465
|
+
|
|
466
|
+
// Signup: Creates anonymous identity and returns trapdoor
|
|
467
|
+
const handleSignup = async () => {
|
|
468
|
+
try {
|
|
469
|
+
const result = await signUp("zkproof");
|
|
470
|
+
|
|
471
|
+
if (result.success && result.seedPhrase) {
|
|
472
|
+
// CRITICAL: User MUST save this trapdoor!
|
|
473
|
+
// It's the ONLY way to recover the anonymous account
|
|
474
|
+
console.log("Your trapdoor (save securely):", result.seedPhrase);
|
|
475
|
+
|
|
476
|
+
// Recommend user to:
|
|
477
|
+
// 1. Write it down on paper
|
|
478
|
+
// 2. Store in password manager
|
|
479
|
+
// 3. Keep multiple secure copies
|
|
480
|
+
alert(`Save this trapdoor securely:\n\n${result.seedPhrase}\n\nYou'll need it to login on other devices!`);
|
|
481
|
+
}
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error("ZK-Proof signup failed:", error);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// Login: Use saved trapdoor to restore anonymous identity
|
|
488
|
+
const handleLogin = async () => {
|
|
489
|
+
try {
|
|
490
|
+
const result = await login("zkproof", trapdoor);
|
|
491
|
+
|
|
492
|
+
if (result.success) {
|
|
493
|
+
console.log("Logged in anonymously!");
|
|
494
|
+
console.log("Identity commitment:", result.userPub);
|
|
495
|
+
}
|
|
496
|
+
} catch (error) {
|
|
497
|
+
console.error("ZK-Proof login failed:", error);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
return (
|
|
502
|
+
<div>
|
|
503
|
+
<h3>Anonymous Authentication with ZK-Proof</h3>
|
|
504
|
+
|
|
505
|
+
<div>
|
|
506
|
+
<button onClick={handleSignup}>
|
|
507
|
+
Create Anonymous Identity
|
|
508
|
+
</button>
|
|
509
|
+
</div>
|
|
510
|
+
|
|
511
|
+
<div>
|
|
512
|
+
<input
|
|
513
|
+
type="text"
|
|
514
|
+
value={trapdoor}
|
|
515
|
+
onChange={(e) => setTrapdoor(e.target.value)}
|
|
516
|
+
placeholder="Enter your trapdoor to login"
|
|
517
|
+
/>
|
|
518
|
+
<button onClick={handleLogin}>
|
|
519
|
+
Login Anonymously
|
|
520
|
+
</button>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Important Notes about ZK-Proof:**
|
|
528
|
+
|
|
529
|
+
- **Trapdoor is Critical**: The trapdoor is like a master password - without it, the account is permanently lost
|
|
530
|
+
- **No Recovery**: Unlike traditional auth, there's no "forgot password" - trapdoor loss means permanent account loss
|
|
531
|
+
- **Complete Anonymity**: Your identity remains private even from the application
|
|
532
|
+
- **Multi-Device Support**: Use the same trapdoor on different devices
|
|
533
|
+
- **Privacy-Preserving**: Uses Semaphore protocol for zero-knowledge proofs
|
|
534
|
+
|
|
535
|
+
### Connection Monitoring
|
|
536
|
+
|
|
537
|
+
```tsx
|
|
538
|
+
function ConnectionStatus() {
|
|
539
|
+
const { useGunConnection, useGunDebug } = useShogun();
|
|
540
|
+
|
|
541
|
+
// Monitor connection status
|
|
542
|
+
const connection = useGunConnection('user/data');
|
|
543
|
+
|
|
544
|
+
// Enable debug logging
|
|
545
|
+
useGunDebug('user/data', true);
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
<div className="connection-status">
|
|
549
|
+
<div className={`status-indicator ${connection.isConnected ? 'connected' : 'disconnected'}`}>
|
|
550
|
+
{connection.isConnected ? '🟢 Connected' : '🔴 Disconnected'}
|
|
551
|
+
</div>
|
|
552
|
+
|
|
553
|
+
{connection.lastSeen && (
|
|
554
|
+
<p>Last seen: {connection.lastSeen.toLocaleTimeString()}</p>
|
|
555
|
+
)}
|
|
556
|
+
|
|
557
|
+
{connection.error && (
|
|
558
|
+
<p className="error">Error: {connection.error}</p>
|
|
559
|
+
)}
|
|
560
|
+
</div>
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## 🎨 Customization
|
|
566
|
+
|
|
567
|
+
### CSS Variables
|
|
568
|
+
|
|
569
|
+
Customize the appearance using CSS variables:
|
|
570
|
+
|
|
571
|
+
```css
|
|
572
|
+
:root {
|
|
573
|
+
/* Primary colors */
|
|
574
|
+
--shogun-primary: #3b82f6;
|
|
575
|
+
--shogun-primary-hover: #2563eb;
|
|
576
|
+
|
|
577
|
+
/* Background colors */
|
|
578
|
+
--shogun-bg: #ffffff;
|
|
579
|
+
--shogun-bg-secondary: #f3f4f6;
|
|
580
|
+
|
|
581
|
+
/* Text colors */
|
|
582
|
+
--shogun-text: #1f2937;
|
|
583
|
+
--shogun-text-secondary: #6b7280;
|
|
584
|
+
|
|
585
|
+
/* Border and shadow */
|
|
586
|
+
--shogun-border: #e5e7eb;
|
|
587
|
+
--shogun-border-radius: 12px;
|
|
588
|
+
--shogun-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
589
|
+
|
|
590
|
+
/* Transitions */
|
|
591
|
+
--shogun-transition: all 0.2s ease;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/* Dark mode overrides */
|
|
595
|
+
@media (prefers-color-scheme: dark) {
|
|
596
|
+
:root {
|
|
597
|
+
--shogun-bg: #1f2937;
|
|
598
|
+
--shogun-bg-secondary: #374151;
|
|
599
|
+
--shogun-text: #f3f4f6;
|
|
600
|
+
--shogun-text-secondary: #9ca3af;
|
|
601
|
+
--shogun-border: #4b5563;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Custom Styling
|
|
607
|
+
|
|
608
|
+
```css
|
|
609
|
+
/* Custom button styles */
|
|
610
|
+
.shogun-connect-button {
|
|
611
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
612
|
+
border-radius: 25px;
|
|
613
|
+
font-weight: 700;
|
|
614
|
+
text-transform: uppercase;
|
|
615
|
+
letter-spacing: 1px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/* Custom modal styles */
|
|
619
|
+
.shogun-modal {
|
|
620
|
+
border-radius: 20px;
|
|
621
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* Custom form styles */
|
|
625
|
+
.shogun-form-group input {
|
|
626
|
+
border-radius: 10px;
|
|
627
|
+
border: 2px solid transparent;
|
|
628
|
+
transition: border-color 0.3s ease;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.shogun-form-group input:focus {
|
|
632
|
+
border-color: var(--shogun-primary);
|
|
633
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
## 🔧 Configuration Options
|
|
638
|
+
|
|
639
|
+
### Complete Configuration Interface
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
interface ShogunConnectorOptions {
|
|
643
|
+
// App information
|
|
644
|
+
appName: string;
|
|
645
|
+
|
|
646
|
+
// Feature toggles
|
|
647
|
+
showMetamask?: boolean;
|
|
648
|
+
showWebauthn?: boolean;
|
|
649
|
+
showNostr?: boolean;
|
|
650
|
+
darkMode?: boolean;
|
|
651
|
+
|
|
652
|
+
// Network configuration (backward compatible)
|
|
653
|
+
peers?: string[];
|
|
654
|
+
authToken?: string;
|
|
655
|
+
gunInstance?: IGunInstance<any>;
|
|
656
|
+
gunOptions?: any;
|
|
657
|
+
|
|
658
|
+
// Transport layer configuration (new in v5.0.0)
|
|
659
|
+
transport?: {
|
|
660
|
+
type: "gun" | "sqlite" | "postgresql" | "mongodb" | "custom";
|
|
661
|
+
options?: any;
|
|
662
|
+
customTransport?: any;
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// Timeouts and provider configs
|
|
666
|
+
timeouts?: {
|
|
667
|
+
login?: number;
|
|
668
|
+
signup?: number;
|
|
669
|
+
operation?: number;
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
// Gun Advanced Plugin configuration
|
|
673
|
+
enableGunDebug?: boolean;
|
|
674
|
+
enableConnectionMonitoring?: boolean;
|
|
675
|
+
defaultPageSize?: number;
|
|
676
|
+
connectionTimeout?: number;
|
|
677
|
+
debounceInterval?: number;
|
|
678
|
+
}
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Connector Result
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
interface ShogunConnectorResult {
|
|
685
|
+
core: ShogunCore;
|
|
686
|
+
options: ShogunConnectorOptions;
|
|
687
|
+
setProvider: (provider: any) => boolean;
|
|
688
|
+
getCurrentProviderUrl: () => string | null;
|
|
689
|
+
registerPlugin: (plugin: any) => boolean;
|
|
690
|
+
hasPlugin: (name: string) => boolean;
|
|
691
|
+
gunPlugin: null;
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
## 🌐 Browser Support
|
|
696
|
+
|
|
697
|
+
- **Chrome** ≥ 60
|
|
698
|
+
- **Firefox** ≥ 60
|
|
699
|
+
- **Safari** ≥ 12
|
|
700
|
+
- **Edge** ≥ 79
|
|
701
|
+
|
|
702
|
+
## 📱 Mobile Support
|
|
703
|
+
|
|
704
|
+
The library is fully responsive and works seamlessly on mobile devices. All authentication methods are optimized for touch interfaces.
|
|
705
|
+
|
|
706
|
+
## 🔒 Security Features
|
|
707
|
+
|
|
708
|
+
- **Encrypted Storage**: Gun pairs can be encrypted with passwords
|
|
709
|
+
- **Secure Authentication**: Multiple secure authentication methods
|
|
710
|
+
- **Session Management**: Automatic session handling and cleanup
|
|
711
|
+
- **Error Handling**: Comprehensive error handling and user feedback
|
|
712
|
+
|
|
713
|
+
## 🚀 Performance
|
|
714
|
+
|
|
715
|
+
- **Lazy Loading**: Components load only when needed
|
|
716
|
+
- **Optimized Rendering**: Efficient React rendering with proper memoization
|
|
717
|
+
- **Connection Pooling**: Smart connection management for optimal performance
|
|
718
|
+
- **Debounced Updates**: Prevents excessive re-renders during rapid data changes
|
|
719
|
+
|
|
720
|
+
## 🤝 Contributing
|
|
721
|
+
|
|
722
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
723
|
+
|
|
724
|
+
### Development Setup
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
# Clone the repository
|
|
728
|
+
git clone https://github.com/shogun/shogun-button-react.git
|
|
729
|
+
|
|
730
|
+
# Install dependencies
|
|
731
|
+
yarn install
|
|
732
|
+
|
|
733
|
+
# Start development server
|
|
734
|
+
yarn dev
|
|
735
|
+
|
|
736
|
+
# Build the library
|
|
737
|
+
yarn build
|
|
738
|
+
|
|
739
|
+
# Run tests
|
|
740
|
+
yarn test
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
## 📄 License
|
|
744
|
+
|
|
745
|
+
MIT © [Shogun](https://github.com/shogun)
|
|
746
|
+
|
|
747
|
+
## 🆘 Support
|
|
748
|
+
|
|
749
|
+
- **Documentation**: [Full API Reference](https://docs.shogun.dev)
|
|
750
|
+
- **Issues**: [GitHub Issues](https://github.com/shogun/shogun-button-react/issues)
|
|
751
|
+
- **Discussions**: [GitHub Discussions](https://github.com/shogun/shogun-button-react/discussions)
|
|
752
|
+
- **Discord**: [Join our community](https://discord.gg/shogun)
|