@jerydam/lumina-sdk 0.1.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.
Files changed (152) hide show
  1. package/BUTTON_FIXES.md +59 -0
  2. package/DOCS_INDEX.md +332 -0
  3. package/DOCUMENTATION.md +252 -0
  4. package/DOCUMENTATION_BUILD_SUMMARY.md +376 -0
  5. package/DOCUMENTATION_COMPLETE.md +311 -0
  6. package/FEATURES.md +333 -0
  7. package/Lumina-sdk/src/components/lumina-provider.tsx +46 -0
  8. package/Lumina-sdk/src/components/transaction-confirm.tsx +242 -0
  9. package/Lumina-sdk/src/components/wallet-display.tsx +157 -0
  10. package/Lumina-sdk/src/components/wallet-login.tsx +163 -0
  11. package/Lumina-sdk/src/hooks/use-mobile.ts +19 -0
  12. package/Lumina-sdk/src/hooks/use-toast.ts +191 -0
  13. package/Lumina-sdk/src/index.ts +0 -0
  14. package/Lumina-sdk/src/lib/api.ts +66 -0
  15. package/Lumina-sdk/src/lib/utils.ts +6 -0
  16. package/Lumina-sdk/src/package.json +42 -0
  17. package/Lumina-sdk/src/tsconfig.json +19 -0
  18. package/NEW_FILES_MANIFEST.txt +146 -0
  19. package/README.md +298 -0
  20. package/app/dashboard/analytics/page.tsx +218 -0
  21. package/app/dashboard/api-keys/page.tsx +260 -0
  22. package/app/dashboard/billing/page.tsx +412 -0
  23. package/app/dashboard/integration/page.tsx +185 -0
  24. package/app/dashboard/layout.tsx +18 -0
  25. package/app/dashboard/page.tsx +244 -0
  26. package/app/dashboard/settings/page.tsx +285 -0
  27. package/app/dashboard/users/page.tsx +148 -0
  28. package/app/docs/api/authentication/page.tsx +246 -0
  29. package/app/docs/api/endpoints/page.tsx +397 -0
  30. package/app/docs/api/errors/page.tsx +305 -0
  31. package/app/docs/api/overview/page.tsx +306 -0
  32. package/app/docs/examples/basic-setup/page.tsx +256 -0
  33. package/app/docs/examples/multi-chain/page.tsx +331 -0
  34. package/app/docs/examples/nextjs-full-stack/page.tsx +332 -0
  35. package/app/docs/getting-started/environment-setup/page.tsx +243 -0
  36. package/app/docs/getting-started/installation/page.tsx +187 -0
  37. package/app/docs/getting-started/introduction/page.tsx +178 -0
  38. package/app/docs/getting-started/quick-start/page.tsx +199 -0
  39. package/app/docs/guides/nextjs/page.tsx +358 -0
  40. package/app/docs/guides/react/page.tsx +230 -0
  41. package/app/docs/guides/security/page.tsx +284 -0
  42. package/app/docs/layout.tsx +32 -0
  43. package/app/docs/page.tsx +180 -0
  44. package/app/docs/sdk/lumina-provider/page.tsx +186 -0
  45. package/app/docs/sdk/transaction-confirm/page.tsx +331 -0
  46. package/app/docs/sdk/wallet-display/page.tsx +224 -0
  47. package/app/docs/sdk/wallet-login/page.tsx +207 -0
  48. package/app/docs/troubleshooting/common-issues/page.tsx +301 -0
  49. package/app/docs/troubleshooting/faq/page.tsx +105 -0
  50. package/app/globals.css +125 -0
  51. package/app/invite/[token]/page.tsx +78 -0
  52. package/app/layout.tsx +36 -0
  53. package/app/login/page.tsx +175 -0
  54. package/app/page.tsx +336 -0
  55. package/app/sdk-demo/page.tsx +239 -0
  56. package/components/dashboard-sidebar.tsx +113 -0
  57. package/components/docs/breadcrumb.tsx +51 -0
  58. package/components/docs/callout.tsx +53 -0
  59. package/components/docs/code-block.tsx +77 -0
  60. package/components/docs/docs-sidebar.tsx +214 -0
  61. package/components/docs/table-of-contents.tsx +83 -0
  62. package/components/sdk/lumina-provider.tsx +46 -0
  63. package/components/sdk/transaction-confirm.tsx +242 -0
  64. package/components/sdk/wallet-display.tsx +157 -0
  65. package/components/sdk/wallet-login.tsx +163 -0
  66. package/components/theme-provider.tsx +11 -0
  67. package/components/ui/accordion.tsx +66 -0
  68. package/components/ui/alert-dialog.tsx +157 -0
  69. package/components/ui/alert.tsx +66 -0
  70. package/components/ui/aspect-ratio.tsx +11 -0
  71. package/components/ui/avatar.tsx +53 -0
  72. package/components/ui/badge.tsx +46 -0
  73. package/components/ui/breadcrumb.tsx +109 -0
  74. package/components/ui/button-group.tsx +83 -0
  75. package/components/ui/button.tsx +60 -0
  76. package/components/ui/calendar.tsx +213 -0
  77. package/components/ui/card.tsx +92 -0
  78. package/components/ui/carousel.tsx +241 -0
  79. package/components/ui/chart.tsx +351 -0
  80. package/components/ui/checkbox.tsx +32 -0
  81. package/components/ui/collapsible.tsx +33 -0
  82. package/components/ui/command.tsx +184 -0
  83. package/components/ui/context-menu.tsx +252 -0
  84. package/components/ui/dialog.tsx +143 -0
  85. package/components/ui/drawer.tsx +135 -0
  86. package/components/ui/dropdown-menu.tsx +257 -0
  87. package/components/ui/empty.tsx +104 -0
  88. package/components/ui/field.tsx +244 -0
  89. package/components/ui/form.tsx +167 -0
  90. package/components/ui/hover-card.tsx +44 -0
  91. package/components/ui/input-group.tsx +169 -0
  92. package/components/ui/input-otp.tsx +77 -0
  93. package/components/ui/input.tsx +21 -0
  94. package/components/ui/item.tsx +193 -0
  95. package/components/ui/kbd.tsx +28 -0
  96. package/components/ui/label.tsx +24 -0
  97. package/components/ui/menubar.tsx +276 -0
  98. package/components/ui/navigation-menu.tsx +166 -0
  99. package/components/ui/pagination.tsx +127 -0
  100. package/components/ui/popover.tsx +48 -0
  101. package/components/ui/progress.tsx +31 -0
  102. package/components/ui/radio-group.tsx +45 -0
  103. package/components/ui/resizable.tsx +56 -0
  104. package/components/ui/scroll-area.tsx +58 -0
  105. package/components/ui/select.tsx +185 -0
  106. package/components/ui/separator.tsx +28 -0
  107. package/components/ui/sheet.tsx +139 -0
  108. package/components/ui/sidebar.tsx +726 -0
  109. package/components/ui/skeleton.tsx +13 -0
  110. package/components/ui/slider.tsx +59 -0
  111. package/components/ui/sonner.tsx +25 -0
  112. package/components/ui/spinner.tsx +16 -0
  113. package/components/ui/switch.tsx +29 -0
  114. package/components/ui/table.tsx +116 -0
  115. package/components/ui/tabs.tsx +66 -0
  116. package/components/ui/textarea.tsx +18 -0
  117. package/components/ui/toast.tsx +129 -0
  118. package/components/ui/toaster.tsx +35 -0
  119. package/components/ui/toggle-group.tsx +73 -0
  120. package/components/ui/toggle.tsx +47 -0
  121. package/components/ui/tooltip.tsx +61 -0
  122. package/components/ui/use-mobile.tsx +19 -0
  123. package/components/ui/use-toast.ts +191 -0
  124. package/components.json +21 -0
  125. package/hooks/use-mobile.ts +19 -0
  126. package/hooks/use-toast.ts +191 -0
  127. package/lib/api.ts +66 -0
  128. package/lib/utils.ts +6 -0
  129. package/next-env.d.ts +6 -0
  130. package/next.config.mjs +11 -0
  131. package/package.json +73 -0
  132. package/pnpm-workspace.yaml +5 -0
  133. package/postcss.config.mjs +8 -0
  134. package/public/apple-icon.png +0 -0
  135. package/public/fav.jpeg +0 -0
  136. package/public/fav.png +0 -0
  137. package/public/icon-dark-32x32.png +0 -0
  138. package/public/icon-light-32x32.png +0 -0
  139. package/public/icon.png +0 -0
  140. package/public/icon.svg +26 -0
  141. package/public/logo.jpeg +0 -0
  142. package/public/logo.png +0 -0
  143. package/public/logo2.jpeg +0 -0
  144. package/public/logo2.png +0 -0
  145. package/public/placeholder-logo.png +0 -0
  146. package/public/placeholder-logo.svg +1 -0
  147. package/public/placeholder-user.jpg +0 -0
  148. package/public/placeholder.jpg +0 -0
  149. package/public/placeholder.svg +1 -0
  150. package/styles/globals.css +209 -0
  151. package/tailwind.config.ts +15 -0
  152. package/tsconfig.json +41 -0
@@ -0,0 +1,285 @@
1
+ 'use client'
2
+
3
+ import { Card } from '@/components/ui/card'
4
+ import { Button } from '@/components/ui/button'
5
+ import { Input } from '@/components/ui/input'
6
+ import { Bell, Lock, Users, Shield, Trash2, Loader2, AlertTriangle, CheckCircle2, UserPlus, X } from 'lucide-react'
7
+ import { useState, useEffect } from 'react'
8
+ import { useRouter } from 'next/navigation'
9
+ import { apiClient } from '@/lib/api'
10
+
11
+ interface DeveloperProfile {
12
+ name: string
13
+ email: string
14
+ plan: string
15
+ }
16
+
17
+ export default function SettingsPage() {
18
+ const router = useRouter()
19
+ const [profile, setProfile] = useState<DeveloperProfile | null>(null)
20
+ const [isLoading, setIsLoading] = useState(true)
21
+ const [message, setMessage] = useState({ type: '', text: '' })
22
+
23
+ // Modals State
24
+ const [showPasswordModal, setShowPasswordModal] = useState(false)
25
+ const [showDeleteModal, setShowDeleteModal] = useState(false)
26
+
27
+ // Forms State
28
+ const [inviteEmail, setInviteEmail] = useState('')
29
+ const [isInviting, setIsInviting] = useState(false)
30
+
31
+ const [passwordForm, setPasswordForm] = useState({ current: '', new: '', confirm: '' })
32
+ const [isChangingPassword, setIsChangingPassword] = useState(false)
33
+
34
+ const [deleteConfirmation, setDeleteConfirmation] = useState('')
35
+ const [isDeleting, setIsDeleting] = useState(false)
36
+
37
+ useEffect(() => {
38
+ const fetchProfile = async () => {
39
+ try {
40
+ setIsLoading(true)
41
+ const data = await apiClient.dashboard('/v1/developers/me')
42
+ setProfile(data)
43
+ } catch (error) {
44
+ console.error('Failed to load profile:', error)
45
+ } finally {
46
+ setIsLoading(false)
47
+ }
48
+ }
49
+ fetchProfile()
50
+ }, [])
51
+
52
+ const handleInviteTeam = async (e: React.FormEvent) => {
53
+ e.preventDefault()
54
+ setIsInviting(true)
55
+ setMessage({ type: '', text: '' })
56
+
57
+ try {
58
+ await apiClient.dashboard('/v1/developers/team/invite', {
59
+ method: 'POST',
60
+ headers: { 'Content-Type': 'application/json' },
61
+ body: JSON.stringify({ email: inviteEmail })
62
+ })
63
+ setMessage({ type: 'success', text: `Invite sent to ${inviteEmail}` })
64
+ setInviteEmail('')
65
+ } catch (err: any) {
66
+ setMessage({ type: 'error', text: err.message || 'Failed to send invite.' })
67
+ } finally {
68
+ setIsInviting(false)
69
+ }
70
+ }
71
+
72
+ const handleChangePassword = async (e: React.FormEvent) => {
73
+ e.preventDefault()
74
+ if (passwordForm.new !== passwordForm.confirm) {
75
+ setMessage({ type: 'error', text: 'New passwords do not match.' })
76
+ return
77
+ }
78
+ if (passwordForm.new.length < 8) {
79
+ setMessage({ type: 'error', text: 'Password must be at least 8 characters.' })
80
+ return
81
+ }
82
+
83
+ setIsChangingPassword(true)
84
+ setMessage({ type: '', text: '' })
85
+
86
+ try {
87
+ await apiClient.dashboard('/v1/developers/password', {
88
+ method: 'PUT',
89
+ body: JSON.stringify({
90
+ current_password: passwordForm.current,
91
+ new_password: passwordForm.new
92
+ })
93
+ })
94
+ setMessage({ type: 'success', text: 'Password updated successfully.' })
95
+ setShowPasswordModal(false)
96
+ setPasswordForm({ current: '', new: '', confirm: '' })
97
+ } catch (err: any) {
98
+ setMessage({ type: 'error', text: err.message || 'Failed to update password.' })
99
+ } finally {
100
+ setIsChangingPassword(false)
101
+ }
102
+ }
103
+
104
+ const handleDeleteAccount = async () => {
105
+ if (deleteConfirmation !== 'DELETE') return
106
+
107
+ setIsDeleting(true)
108
+ try {
109
+ await apiClient.dashboard('/v1/developers/me', { method: 'DELETE' })
110
+ localStorage.removeItem('lumina_dev_token')
111
+ router.push('/login')
112
+ } catch (err: any) {
113
+ setMessage({ type: 'error', text: err.message || 'Failed to delete account.' })
114
+ setIsDeleting(false)
115
+ setShowDeleteModal(false)
116
+ }
117
+ }
118
+
119
+ if (isLoading) {
120
+ return (
121
+ <div className="min-h-[60vh] flex items-center justify-center">
122
+ <Loader2 className="w-8 h-8 animate-spin text-emerald-500" />
123
+ </div>
124
+ )
125
+ }
126
+
127
+ return (
128
+ <div className="space-y-8 relative">
129
+ <div>
130
+ <h1 className="text-4xl font-bold mb-2">Settings</h1>
131
+ <p className="text-foreground/60">Manage your developer profile and workspace preferences</p>
132
+ </div>
133
+
134
+ {message.text && (
135
+ <div className={`p-4 rounded-lg border flex items-center gap-3 ${
136
+ message.type === 'error' ? 'bg-red-500/10 border-red-500/50 text-red-400' : 'bg-emerald-500/10 border-emerald-500/50 text-emerald-400'
137
+ }`}>
138
+ {message.type === 'error' ? <AlertTriangle size={20} /> : <CheckCircle2 size={20} />}
139
+ {message.text}
140
+ </div>
141
+ )}
142
+
143
+ {/* Account Settings */}
144
+ <Card className="glassmorphism-dark p-6 border-border">
145
+ <h2 className="text-2xl font-semibold mb-6">Account Information</h2>
146
+ <div className="space-y-6">
147
+ <div>
148
+ <label className="block text-sm font-medium mb-2">Developer Name</label>
149
+ <Input defaultValue={profile?.name || ''} className="bg-white/5 border-border text-foreground/80" readOnly />
150
+ </div>
151
+ <div>
152
+ <label className="block text-sm font-medium mb-2">Email Address</label>
153
+ <Input type="email" defaultValue={profile?.email || ''} className="bg-white/5 border-border text-foreground/80" readOnly />
154
+ </div>
155
+ </div>
156
+ </Card>
157
+
158
+ {/* Team Management UI */}
159
+ <Card className="glassmorphism-dark p-6 border-border">
160
+ <div className="flex items-center justify-between mb-6">
161
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
162
+ <Users size={24} />
163
+ Team Members
164
+ </h2>
165
+ </div>
166
+
167
+ <form onSubmit={handleInviteTeam} className="flex gap-2 mb-6">
168
+ <Input
169
+ type="email"
170
+ placeholder="colleague@company.com"
171
+ value={inviteEmail}
172
+ onChange={(e) => setInviteEmail(e.target.value)}
173
+ className="bg-white/5 border-border"
174
+ required
175
+ />
176
+ <Button type="submit" disabled={isInviting} className="bg-emerald-600 hover:bg-emerald-700 whitespace-nowrap gap-2">
177
+ {isInviting ? <Loader2 className="animate-spin" size={16} /> : <UserPlus size={16} />}
178
+ Invite Member
179
+ </Button>
180
+ </form>
181
+
182
+ <div className="space-y-4">
183
+ <div className="flex items-center justify-between p-4 bg-white/5 rounded-lg border border-border/50">
184
+ <div>
185
+ <p className="font-medium">{profile?.name || 'You'}</p>
186
+ <p className="text-sm text-foreground/60">{profile?.email}</p>
187
+ </div>
188
+ <span className="px-3 py-1 text-sm rounded-lg bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">Owner</span>
189
+ </div>
190
+ </div>
191
+ </Card>
192
+
193
+ {/* Security */}
194
+ <Card className="glassmorphism-dark p-6 border-border">
195
+ <h2 className="text-2xl font-semibold mb-6 flex items-center gap-2">
196
+ <Lock size={24} />
197
+ Security
198
+ </h2>
199
+ <div className="p-4 bg-white/5 rounded-lg border border-border/50 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
200
+ <div>
201
+ <p className="font-medium mb-1">Password</p>
202
+ <p className="text-sm text-foreground/60">Update your dashboard login password</p>
203
+ </div>
204
+ <Button onClick={() => setShowPasswordModal(true)} variant="outline">Change Password</Button>
205
+ </div>
206
+ </Card>
207
+
208
+ {/* Danger Zone */}
209
+ <Card className="glassmorphism-dark p-6 border-red-600/30 bg-red-600/5">
210
+ <h2 className="text-2xl font-semibold mb-6 text-red-500">Danger Zone</h2>
211
+ <div className="p-4 bg-red-600/10 rounded-lg border border-red-600/30">
212
+ <p className="font-medium mb-1">Delete Workspace</p>
213
+ <p className="text-sm text-foreground/60 mb-4">Permanently delete your account, API keys, and sever all active embedded wallets.</p>
214
+ <Button onClick={() => setShowDeleteModal(true)} variant="outline" className="border-red-600/30 text-red-500 hover:bg-red-600/10 gap-2">
215
+ <Trash2 size={18} />
216
+ Delete Account
217
+ </Button>
218
+ </div>
219
+ </Card>
220
+
221
+ {/* ── Modals ── */}
222
+
223
+ {/* Password Modal */}
224
+ {showPasswordModal && (
225
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm p-4">
226
+ <Card className="glassmorphism-dark w-full max-w-md p-6 border-border shadow-2xl relative">
227
+ <button onClick={() => setShowPasswordModal(false)} className="absolute top-4 right-4 text-foreground/50 hover:text-foreground">
228
+ <X size={20} />
229
+ </button>
230
+ <h2 className="text-xl font-bold mb-6">Change Password</h2>
231
+ <form onSubmit={handleChangePassword} className="space-y-4">
232
+ <div>
233
+ <label className="block text-sm font-medium mb-1">Current Password</label>
234
+ <Input type="password" required value={passwordForm.current} onChange={(e) => setPasswordForm({...passwordForm, current: e.target.value})} className="bg-white/5 border-border" />
235
+ </div>
236
+ <div>
237
+ <label className="block text-sm font-medium mb-1">New Password</label>
238
+ <Input type="password" required minLength={8} value={passwordForm.new} onChange={(e) => setPasswordForm({...passwordForm, new: e.target.value})} className="bg-white/5 border-border" />
239
+ </div>
240
+ <div>
241
+ <label className="block text-sm font-medium mb-1">Confirm New Password</label>
242
+ <Input type="password" required minLength={8} value={passwordForm.confirm} onChange={(e) => setPasswordForm({...passwordForm, confirm: e.target.value})} className="bg-white/5 border-border" />
243
+ </div>
244
+ <Button type="submit" disabled={isChangingPassword} className="w-full bg-emerald-600 hover:bg-emerald-700 mt-2">
245
+ {isChangingPassword ? <Loader2 className="animate-spin" size={18} /> : 'Update Password'}
246
+ </Button>
247
+ </form>
248
+ </Card>
249
+ </div>
250
+ )}
251
+
252
+ {/* Delete Modal */}
253
+ {showDeleteModal && (
254
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm p-4">
255
+ <Card className="glassmorphism-dark w-full max-w-md p-6 border-red-600/50 shadow-2xl relative bg-red-950/20">
256
+ <button onClick={() => setShowDeleteModal(false)} className="absolute top-4 right-4 text-foreground/50 hover:text-foreground">
257
+ <X size={20} />
258
+ </button>
259
+ <div className="flex items-center gap-3 text-red-500 mb-4">
260
+ <AlertTriangle size={28} />
261
+ <h2 className="text-xl font-bold">Delete Workspace?</h2>
262
+ </div>
263
+ <p className="text-sm text-foreground/80 mb-6">
264
+ This action is irreversible. All your API keys will be revoked, gas balances lost, and embedded wallets disconnected.
265
+ To confirm, type <strong>DELETE</strong> below.
266
+ </p>
267
+ <Input
268
+ value={deleteConfirmation}
269
+ onChange={(e) => setDeleteConfirmation(e.target.value)}
270
+ placeholder="DELETE"
271
+ className="bg-white/5 border-red-600/30 mb-6 focus:border-red-500"
272
+ />
273
+ <Button
274
+ onClick={handleDeleteAccount}
275
+ disabled={deleteConfirmation !== 'DELETE' || isDeleting}
276
+ className="w-full bg-red-600 hover:bg-red-700 text-white"
277
+ >
278
+ {isDeleting ? <Loader2 className="animate-spin" size={18} /> : 'Permanently Delete Account'}
279
+ </Button>
280
+ </Card>
281
+ </div>
282
+ )}
283
+ </div>
284
+ )
285
+ }
@@ -0,0 +1,148 @@
1
+ 'use client'
2
+
3
+ import { Search, Filter, Download, ExternalLink, Shield, Loader2 } from 'lucide-react'
4
+ import { Card } from '@/components/ui/card'
5
+ import { Button } from '@/components/ui/button'
6
+ import { Input } from '@/components/ui/input'
7
+ import { useState, useEffect } from 'react'
8
+ import { apiClient } from '@/lib/api'
9
+
10
+ interface UserWallet {
11
+ id: string
12
+ signer_address: string
13
+ oauth_provider: string
14
+ created_at: string
15
+ account_count: number
16
+ }
17
+
18
+ export default function UsersPage() {
19
+ const [wallets, setWallets] = useState<UserWallet[]>([])
20
+ const [isLoading, setIsLoading] = useState(true)
21
+ const [page, setPage] = useState(0)
22
+ const limit = 10
23
+
24
+ const fetchUsers = async (pageIndex: number) => {
25
+ try {
26
+ setIsLoading(true)
27
+ const offset = pageIndex * limit
28
+ const data = await apiClient.dashboard(`/v1/wallets?limit=${limit}&offset=${offset}`)
29
+ setWallets(data.wallets || [])
30
+ } catch (error) {
31
+ console.error('Failed to fetch users:', error)
32
+ } finally {
33
+ setIsLoading(false)
34
+ }
35
+ }
36
+
37
+ useEffect(() => {
38
+ fetchUsers(page)
39
+ }, [page])
40
+
41
+ return (
42
+ <div className="space-y-8">
43
+ {/* Header */}
44
+ <div>
45
+ <h1 className="text-4xl font-bold mb-2">Users & Wallets</h1>
46
+ <p className="text-foreground/60">Manage your application's embedded wallets and signers</p>
47
+ </div>
48
+
49
+ {/* Filters and Actions */}
50
+ <Card className="glassmorphism-dark p-6 border-border">
51
+ <div className="flex flex-col md:flex-row gap-4 items-end">
52
+ <div className="flex-1">
53
+ <label className="block text-sm font-medium mb-2">Search</label>
54
+ <div className="relative">
55
+ <Search className="absolute left-3 top-3 text-foreground/40" size={20} />
56
+ <Input
57
+ placeholder="Search by signer address..."
58
+ className="pl-10 bg-white/5 border-border"
59
+ />
60
+ </div>
61
+ </div>
62
+ <Button variant="outline" className="gap-2">
63
+ <Filter size={18} /> Filter
64
+ </Button>
65
+ <Button variant="outline" className="gap-2">
66
+ <Download size={18} /> Export
67
+ </Button>
68
+ </div>
69
+ </Card>
70
+
71
+ {/* Users Table */}
72
+ <Card className="glassmorphism-dark border-border overflow-hidden">
73
+ <div className="overflow-x-auto">
74
+ <table className="w-full text-sm">
75
+ <thead>
76
+ <tr className="border-b border-border bg-white/5">
77
+ <th className="text-left py-4 px-6 text-foreground/60 font-medium">Signer Address</th>
78
+ <th className="text-left py-4 px-6 text-foreground/60 font-medium">Auth Provider</th>
79
+ <th className="text-left py-4 px-6 text-foreground/60 font-medium">Networks Deployed</th>
80
+ <th className="text-left py-4 px-6 text-foreground/60 font-medium">Created Date</th>
81
+ <th className="text-right py-4 px-6 text-foreground/60 font-medium">Actions</th>
82
+ </tr>
83
+ </thead>
84
+ <tbody>
85
+ {isLoading ? (
86
+ <tr>
87
+ <td colSpan={5} className="py-12 text-center">
88
+ <Loader2 className="w-6 h-6 animate-spin mx-auto text-emerald-500" />
89
+ </td>
90
+ </tr>
91
+ ) : wallets.length === 0 ? (
92
+ <tr>
93
+ <td colSpan={5} className="py-12 text-center text-foreground/60">
94
+ No users have created wallets yet.
95
+ </td>
96
+ </tr>
97
+ ) : (
98
+ wallets.map((wallet) => (
99
+ <tr key={wallet.id} className="border-b border-border/50 hover:bg-white/5 transition">
100
+ <td className="py-4 px-6 font-mono text-sm">{wallet.signer_address}</td>
101
+ <td className="py-4 px-6">
102
+ <div className="flex items-center gap-2">
103
+ <Shield size={16} className="text-emerald-500" />
104
+ <span className="capitalize">{wallet.oauth_provider}</span>
105
+ </div>
106
+ </td>
107
+ <td className="py-4 px-6 font-medium">{wallet.account_count}</td>
108
+ <td className="py-4 px-6 text-foreground/70">
109
+ {new Date(wallet.created_at).toLocaleDateString()}
110
+ </td>
111
+ <td className="py-4 px-6 text-right">
112
+ <button className="p-2 hover:bg-white/10 rounded-lg transition text-foreground/60 hover:text-emerald-400">
113
+ <ExternalLink size={18} />
114
+ </button>
115
+ </td>
116
+ </tr>
117
+ ))
118
+ )}
119
+ </tbody>
120
+ </table>
121
+ </div>
122
+
123
+ {/* Pagination */}
124
+ <div className="px-6 py-4 border-t border-border flex items-center justify-between">
125
+ <p className="text-sm text-foreground/60">Page {page + 1}</p>
126
+ <div className="flex gap-2">
127
+ <Button
128
+ variant="outline"
129
+ size="sm"
130
+ onClick={() => setPage(Math.max(0, page - 1))}
131
+ disabled={page === 0 || isLoading}
132
+ >
133
+ Previous
134
+ </Button>
135
+ <Button
136
+ variant="outline"
137
+ size="sm"
138
+ onClick={() => setPage(page + 1)}
139
+ disabled={wallets.length < limit || isLoading}
140
+ >
141
+ Next
142
+ </Button>
143
+ </div>
144
+ </div>
145
+ </Card>
146
+ </div>
147
+ )
148
+ }
@@ -0,0 +1,246 @@
1
+ import { Breadcrumb } from '@/components/docs/breadcrumb'
2
+ import { CodeBlock } from '@/components/docs/code-block'
3
+ import { Callout } from '@/components/docs/callout'
4
+
5
+ export const metadata = {
6
+ title: 'Authentication API - API Reference',
7
+ description: 'Authenticate users and manage sessions with the Lumina API.',
8
+ }
9
+
10
+ export default function AuthenticationPage() {
11
+ return (
12
+ <>
13
+ <Breadcrumb />
14
+
15
+ <div className="space-y-8">
16
+ <div className="space-y-4">
17
+ <h1 className="text-4xl font-bold text-white">Authentication API</h1>
18
+ <p className="text-lg text-foreground/80">
19
+ Handle user authentication, session management, and credential verification via the Lumina REST API.
20
+ </p>
21
+ </div>
22
+
23
+ <div className="space-y-4">
24
+ <h2 className="text-2xl font-bold">Authentication Methods</h2>
25
+ <p className="text-foreground/80 mb-4">
26
+ Lumina supports multiple authentication methods:
27
+ </p>
28
+ <div className="space-y-3">
29
+ <div className="p-4 rounded-lg bg-white/5 border border-white/10">
30
+ <p className="font-semibold text-emerald-400 mb-2">Bearer Token (API Key)</p>
31
+ <p className="text-sm text-foreground/80">
32
+ Use your API key as a Bearer token in the Authorization header.
33
+ </p>
34
+ </div>
35
+ <div className="p-4 rounded-lg bg-white/5 border border-white/10">
36
+ <p className="font-semibold text-emerald-400 mb-2">Session Tokens</p>
37
+ <p className="text-sm text-foreground/80">
38
+ JWT tokens issued after successful user authentication.
39
+ </p>
40
+ </div>
41
+ <div className="p-4 rounded-lg bg-white/5 border border-white/10">
42
+ <p className="font-semibold text-emerald-400 mb-2">OAuth 2.0</p>
43
+ <p className="text-sm text-foreground/80">
44
+ Standard OAuth 2.0 flow for delegated access.
45
+ </p>
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <div className="space-y-4">
51
+ <h2 className="text-2xl font-bold">Login</h2>
52
+ <p className="text-foreground/80 mb-4">
53
+ Authenticate a user with email and password or email verification code.
54
+ </p>
55
+
56
+ <CodeBlock
57
+ code="POST /auth/login"
58
+ language="http"
59
+ title="Endpoint"
60
+ />
61
+
62
+ <CodeBlock
63
+ code={`{
64
+ "email": "user@example.com",
65
+ "password": "secure_password_or_code"
66
+ }`}
67
+ language="json"
68
+ title="Request Body"
69
+ />
70
+
71
+ <CodeBlock
72
+ code={`{
73
+ "success": true,
74
+ "user": {
75
+ "id": "user_123",
76
+ "email": "user@example.com",
77
+ "walletAddress": "0x...",
78
+ "createdAt": "2024-01-15T10:30:00Z"
79
+ },
80
+ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
81
+ }`}
82
+ language="json"
83
+ title="Response"
84
+ />
85
+ </div>
86
+
87
+ <div className="space-y-4">
88
+ <h2 className="text-2xl font-bold">Request Verification Email</h2>
89
+ <p className="text-foreground/80 mb-4">
90
+ Send a verification code to the user's email.
91
+ </p>
92
+
93
+ <CodeBlock
94
+ code="POST /auth/send-verification-email"
95
+ language="http"
96
+ title="Endpoint"
97
+ />
98
+
99
+ <CodeBlock
100
+ code={`{
101
+ "email": "user@example.com"
102
+ }`}
103
+ language="json"
104
+ title="Request Body"
105
+ />
106
+
107
+ <CodeBlock
108
+ code={`{
109
+ "success": true,
110
+ "message": "Verification email sent"
111
+ }`}
112
+ language="json"
113
+ title="Response"
114
+ />
115
+ </div>
116
+
117
+ <div className="space-y-4">
118
+ <h2 className="text-2xl font-bold">Register</h2>
119
+ <p className="text-foreground/80 mb-4">
120
+ Create a new user account.
121
+ </p>
122
+
123
+ <CodeBlock
124
+ code="POST /auth/register"
125
+ language="http"
126
+ title="Endpoint"
127
+ />
128
+
129
+ <CodeBlock
130
+ code={`{
131
+ "email": "newuser@example.com",
132
+ "password": "secure_password",
133
+ "authMethod": "email"
134
+ }`}
135
+ language="json"
136
+ title="Request Body"
137
+ />
138
+
139
+ <CodeBlock
140
+ code={`{
141
+ "success": true,
142
+ "user": {
143
+ "id": "user_456",
144
+ "email": "newuser@example.com",
145
+ "walletAddress": "0x...",
146
+ "createdAt": "2024-01-15T10:35:00Z"
147
+ }
148
+ }`}
149
+ language="json"
150
+ title="Response"
151
+ />
152
+ </div>
153
+
154
+ <div className="space-y-4">
155
+ <h2 className="text-2xl font-bold">Verify Token</h2>
156
+ <p className="text-foreground/80 mb-4">
157
+ Verify that a session token is valid and not expired.
158
+ </p>
159
+
160
+ <CodeBlock
161
+ code="GET /auth/verify"
162
+ language="http"
163
+ title="Endpoint"
164
+ />
165
+
166
+ <CodeBlock
167
+ code={`Authorization: Bearer <token>`}
168
+ language="http"
169
+ title="Request Headers"
170
+ />
171
+
172
+ <CodeBlock
173
+ code={`{
174
+ "valid": true,
175
+ "user": {
176
+ "id": "user_123",
177
+ "email": "user@example.com",
178
+ "walletAddress": "0x...",
179
+ "expiresAt": "2024-01-22T10:30:00Z"
180
+ }
181
+ }`}
182
+ language="json"
183
+ title="Response"
184
+ />
185
+ </div>
186
+
187
+ <Callout type="warning" title="Token Expiration">
188
+ Session tokens expire after 7 days. Use refresh tokens to obtain new session tokens without requiring re-authentication.
189
+ </Callout>
190
+
191
+ <div className="space-y-4">
192
+ <h2 className="text-2xl font-bold">Logout</h2>
193
+ <p className="text-foreground/80 mb-4">
194
+ Invalidate a session token.
195
+ </p>
196
+
197
+ <CodeBlock
198
+ code="POST /auth/logout"
199
+ language="http"
200
+ title="Endpoint"
201
+ />
202
+
203
+ <CodeBlock
204
+ code={`Authorization: Bearer <token>`}
205
+ language="http"
206
+ title="Request Headers"
207
+ />
208
+
209
+ <CodeBlock
210
+ code={`{
211
+ "success": true,
212
+ "message": "Successfully logged out"
213
+ }`}
214
+ language="json"
215
+ title="Response"
216
+ />
217
+ </div>
218
+
219
+ <div className="space-y-4">
220
+ <h2 className="text-2xl font-bold">Error Responses</h2>
221
+ <CodeBlock
222
+ code={`{
223
+ "error": {
224
+ "code": "INVALID_CREDENTIALS",
225
+ "message": "Email or password is incorrect",
226
+ "status": 401
227
+ }
228
+ }`}
229
+ language="json"
230
+ />
231
+
232
+ <div className="space-y-2 text-sm">
233
+ <p className="text-foreground/80 font-semibold">Common error codes:</p>
234
+ <ul className="space-y-1 text-foreground/70 ml-4">
235
+ <li>• <code className="bg-black/40 px-2 py-1 rounded text-xs">INVALID_CREDENTIALS</code> - Wrong email/password</li>
236
+ <li>• <code className="bg-black/40 px-2 py-1 rounded text-xs">USER_NOT_FOUND</code> - Email not registered</li>
237
+ <li>• <code className="bg-black/40 px-2 py-1 rounded text-xs">EMAIL_ALREADY_EXISTS</code> - Account already exists</li>
238
+ <li>• <code className="bg-black/40 px-2 py-1 rounded text-xs">INVALID_TOKEN</code> - Token is expired or invalid</li>
239
+ <li>• <code className="bg-black/40 px-2 py-1 rounded text-xs">RATE_LIMITED</code> - Too many requests</li>
240
+ </ul>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </>
245
+ )
246
+ }