miragedev-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.
- package/LICENSE +21 -0
- package/README.md +393 -0
- package/dist/auth/biometric.cjs +85 -0
- package/dist/auth/biometric.d.cts +7 -0
- package/dist/auth/biometric.d.ts +7 -0
- package/dist/auth/biometric.js +81 -0
- package/dist/auth/client.cjs +44 -0
- package/dist/auth/client.d.cts +12 -0
- package/dist/auth/client.d.ts +12 -0
- package/dist/auth/client.js +40 -0
- package/dist/auth/index.cjs +17 -0
- package/dist/auth/index.d.cts +6 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/middleware.cjs +37 -0
- package/dist/auth/middleware.d.cts +10 -0
- package/dist/auth/middleware.d.ts +10 -0
- package/dist/auth/middleware.js +35 -0
- package/dist/auth-BC8JI28z.d.cts +22 -0
- package/dist/auth-BC8JI28z.d.ts +22 -0
- package/dist/billing/client.cjs +43 -0
- package/dist/billing/client.d.cts +11 -0
- package/dist/billing/client.d.ts +11 -0
- package/dist/billing/client.js +40 -0
- package/dist/billing/index.cjs +139 -0
- package/dist/billing/index.d.cts +12 -0
- package/dist/billing/index.d.ts +12 -0
- package/dist/billing/index.js +130 -0
- package/dist/billing/mobile.cjs +81 -0
- package/dist/billing/mobile.d.cts +17 -0
- package/dist/billing/mobile.d.ts +17 -0
- package/dist/billing/mobile.js +74 -0
- package/dist/billing/webhook.cjs +84 -0
- package/dist/billing/webhook.d.cts +19 -0
- package/dist/billing/webhook.d.ts +19 -0
- package/dist/billing/webhook.js +78 -0
- package/dist/billing-Bv2V7KWF.d.cts +23 -0
- package/dist/billing-Bv2V7KWF.d.ts +23 -0
- package/dist/chunk-5YXI4Q2K.js +13813 -0
- package/dist/chunk-75ZPJI57.cjs +9 -0
- package/dist/chunk-BW4BLEIM.cjs +18 -0
- package/dist/chunk-DZDDLA4G.js +271 -0
- package/dist/chunk-E5YC2MHX.cjs +13816 -0
- package/dist/chunk-JUTTFY3W.js +16 -0
- package/dist/chunk-M26EDKMY.cjs +280 -0
- package/dist/chunk-M3DPIKWT.js +23 -0
- package/dist/chunk-MLKGABMK.js +7 -0
- package/dist/chunk-PHTUPKEM.cjs +26 -0
- package/dist/cli/commands/init.cjs +11 -0
- package/dist/cli/commands/init.d.cts +3 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.js +2 -0
- package/dist/cli/index.cjs +11 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/email/index.cjs +526 -0
- package/dist/email/index.d.cts +6 -0
- package/dist/email/index.d.ts +6 -0
- package/dist/email/index.js +523 -0
- package/dist/email-DZN1-bHa.d.cts +19 -0
- package/dist/email-DZN1-bHa.d.ts +19 -0
- package/dist/index.cjs +27 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +21 -0
- package/dist/mobile/index.cjs +101 -0
- package/dist/mobile/index.d.cts +15 -0
- package/dist/mobile/index.d.ts +15 -0
- package/dist/mobile/index.js +96 -0
- package/dist/pwa/index.cjs +80 -0
- package/dist/pwa/index.d.cts +51 -0
- package/dist/pwa/index.d.ts +51 -0
- package/dist/pwa/index.js +76 -0
- package/package.json +140 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MirageDev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# MirageDev SDK
|
|
2
|
+
|
|
3
|
+
AI-first SDK for building SAAS applications with Next.js. Build production-ready SAAS apps in minutes, not weeks.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/miragedev-sdk)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🔐 **Authentication** - NextAuth.js, Clerk, Supabase support with biometric auth
|
|
11
|
+
- 💳 **Billing** - Stripe integration with mobile-optimized checkout
|
|
12
|
+
- 📧 **Email** - Beautiful React Email templates with Resend/SendGrid
|
|
13
|
+
- 📱 **PWA** - Progressive Web App with offline support
|
|
14
|
+
- 🎯 **Mobile-First** - Optimized hooks for mobile experiences
|
|
15
|
+
- 🤖 **AI-Friendly** - Comprehensive JSDoc for AI code generation
|
|
16
|
+
- 📦 **Modular** - Import only what you need
|
|
17
|
+
- 🔒 **Type-Safe** - Full TypeScript support with Zod validation
|
|
18
|
+
|
|
19
|
+
## Quick Start (5 minutes)
|
|
20
|
+
|
|
21
|
+
### 1. Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install miragedev-sdk
|
|
25
|
+
# or
|
|
26
|
+
pnpm add miragedev-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Initialize with CLI
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx miragedev init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The CLI will guide you through selecting providers and generating configuration files.
|
|
36
|
+
|
|
37
|
+
**What gets created:**
|
|
38
|
+
- `miragedev.config.ts` - SDK configuration
|
|
39
|
+
- `.env.local.example` - Environment variables template
|
|
40
|
+
- `miragedev.init.ts` - Initialization file
|
|
41
|
+
- `AGENTS.md` - Instructions for AI assistants (Copilot, Cursor, etc.)
|
|
42
|
+
|
|
43
|
+
### 3. Configure Environment
|
|
44
|
+
|
|
45
|
+
Create `.env.local`:
|
|
46
|
+
|
|
47
|
+
```env
|
|
48
|
+
# Auth
|
|
49
|
+
AUTH_SECRET=your-secret-key-here
|
|
50
|
+
|
|
51
|
+
# Billing (Stripe)
|
|
52
|
+
STRIPE_SECRET_KEY=sk_test_xxx
|
|
53
|
+
STRIPE_WEBHOOK_SECRET=whsec_xxx
|
|
54
|
+
|
|
55
|
+
# Email (Resend)
|
|
56
|
+
RESEND_API_KEY=re_xxx
|
|
57
|
+
EMAIL_FROM=noreply@yourapp.com
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 4. Initialize SDK
|
|
61
|
+
|
|
62
|
+
Create `lib/miragedev.ts`:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { initMirageDev } from 'miragedev-sdk'
|
|
66
|
+
|
|
67
|
+
initMirageDev({
|
|
68
|
+
auth: {
|
|
69
|
+
provider: 'nextauth',
|
|
70
|
+
sessionSecret: process.env.AUTH_SECRET!,
|
|
71
|
+
},
|
|
72
|
+
billing: {
|
|
73
|
+
provider: 'stripe',
|
|
74
|
+
stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
|
|
75
|
+
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
|
|
76
|
+
},
|
|
77
|
+
email: {
|
|
78
|
+
provider: 'resend',
|
|
79
|
+
apiKey: process.env.RESEND_API_KEY!,
|
|
80
|
+
from: process.env.EMAIL_FROM!,
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Import this in your root layout (`app/layout.tsx`).
|
|
86
|
+
|
|
87
|
+
### 5. Start Building
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Server Component - Protected Page
|
|
91
|
+
import { requireAuth } from 'miragedev-sdk/auth'
|
|
92
|
+
|
|
93
|
+
export default async function DashboardPage() {
|
|
94
|
+
const session = await requireAuth() // Throws if not authenticated
|
|
95
|
+
return <div>Welcome {session.user.name}!</div>
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Client Component - Subscription Button
|
|
101
|
+
'use client'
|
|
102
|
+
import { useSubscription } from 'miragedev-sdk/billing/client'
|
|
103
|
+
|
|
104
|
+
export function UpgradeButton() {
|
|
105
|
+
const { subscription, isLoading } = useSubscription()
|
|
106
|
+
|
|
107
|
+
if (subscription?.status === 'active') {
|
|
108
|
+
return <button>Manage Subscription</button>
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return <button>Upgrade to Pro</button>
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
### Auth Module
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { requireAuth, getSession } from 'miragedev-sdk/auth'
|
|
121
|
+
import { authMiddleware } from 'miragedev-sdk/auth/middleware'
|
|
122
|
+
import { useSession, signIn, signOut } from 'miragedev-sdk/auth/client'
|
|
123
|
+
import { enableBiometric, signInWithBiometric } from 'miragedev-sdk/auth/biometric'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Server-Side:**
|
|
127
|
+
- `requireAuth()` - Require authentication, throws error if not authenticated
|
|
128
|
+
- `getSession()` - Get current session or null
|
|
129
|
+
|
|
130
|
+
**Client-Side:**
|
|
131
|
+
- `useSession()` - React hook for session state
|
|
132
|
+
- `signIn(provider?)` - Sign in with optional provider
|
|
133
|
+
- `signOut()` - Sign out current user
|
|
134
|
+
|
|
135
|
+
**Middleware:**
|
|
136
|
+
```typescript
|
|
137
|
+
// middleware.ts
|
|
138
|
+
export default authMiddleware({
|
|
139
|
+
publicRoutes: ['/', '/pricing'],
|
|
140
|
+
redirectTo: '/login'
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Biometric:**
|
|
145
|
+
```typescript
|
|
146
|
+
await enableBiometric() // Enable for current user
|
|
147
|
+
const session = await signInWithBiometric() // Sign in with biometric
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Billing Module
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import {
|
|
154
|
+
createCheckout,
|
|
155
|
+
createPortal,
|
|
156
|
+
getSubscription,
|
|
157
|
+
cancelSubscription
|
|
158
|
+
} from 'miragedev-sdk/billing'
|
|
159
|
+
import { useSubscription, openBillingPortal } from 'miragedev-sdk/billing/client'
|
|
160
|
+
import { createMobileCheckout, createPaymentIntent } from 'miragedev-sdk/billing/mobile'
|
|
161
|
+
import { handleWebhook } from 'miragedev-sdk/billing/webhook'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Checkout:**
|
|
165
|
+
```typescript
|
|
166
|
+
const { url } = await createCheckout({
|
|
167
|
+
priceId: 'price_xxx',
|
|
168
|
+
userId: session.user.id,
|
|
169
|
+
successUrl: 'https://yourapp.com/success',
|
|
170
|
+
cancelUrl: 'https://yourapp.com/cancel',
|
|
171
|
+
})
|
|
172
|
+
redirect(url)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Webhooks:**
|
|
176
|
+
```typescript
|
|
177
|
+
// app/api/webhooks/stripe/route.ts
|
|
178
|
+
export async function POST(req: Request) {
|
|
179
|
+
return handleWebhook(req, {
|
|
180
|
+
onSubscriptionCreated: async (data) => {
|
|
181
|
+
await db.user.update({
|
|
182
|
+
where: { id: data.userId },
|
|
183
|
+
data: { isPro: true }
|
|
184
|
+
})
|
|
185
|
+
},
|
|
186
|
+
onSubscriptionCanceled: async (data) => {
|
|
187
|
+
// Handle cancellation
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Mobile:**
|
|
194
|
+
```typescript
|
|
195
|
+
// For mobile PWA checkout
|
|
196
|
+
const { clientSecret } = await createMobileCheckout({
|
|
197
|
+
priceId: 'price_xxx',
|
|
198
|
+
userId: user.id,
|
|
199
|
+
successUrl: 'myapp://success',
|
|
200
|
+
cancelUrl: 'myapp://cancel',
|
|
201
|
+
})
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Email Module
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { sendEmail, sendTemplateEmail } from 'miragedev-sdk/email'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Basic Email:**
|
|
211
|
+
```typescript
|
|
212
|
+
await sendEmail({
|
|
213
|
+
to: 'user@example.com',
|
|
214
|
+
subject: 'Welcome!',
|
|
215
|
+
html: '<p>Hello World</p>',
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Template Email:**
|
|
220
|
+
```typescript
|
|
221
|
+
await sendTemplateEmail({
|
|
222
|
+
to: 'user@example.com',
|
|
223
|
+
template: 'welcome',
|
|
224
|
+
data: {
|
|
225
|
+
userName: 'John',
|
|
226
|
+
actionUrl: 'https://app.com/onboarding'
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Available Templates:**
|
|
232
|
+
- `welcome` - Welcome new users
|
|
233
|
+
- `reset-password` - Password reset
|
|
234
|
+
- `subscription-created` - Subscription confirmation
|
|
235
|
+
- `subscription-canceled` - Cancellation notice
|
|
236
|
+
- `invoice` - Invoice notification
|
|
237
|
+
|
|
238
|
+
### PWA Module
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { configurePWA } from 'miragedev-sdk/pwa'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
export const pwaConfig = configurePWA({
|
|
246
|
+
name: 'My SaaS App',
|
|
247
|
+
shortName: 'MySaaS',
|
|
248
|
+
theme: '#000000',
|
|
249
|
+
backgroundColor: '#ffffff',
|
|
250
|
+
offline: {
|
|
251
|
+
enabled: true,
|
|
252
|
+
pages: ['/', '/dashboard']
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// Use pwaConfig.manifest in Next.js metadata
|
|
257
|
+
// Write pwaConfig.serviceWorker to public/sw.js
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Mobile Module
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import {
|
|
264
|
+
useNetworkStatus,
|
|
265
|
+
useInstallPrompt,
|
|
266
|
+
useNotifications,
|
|
267
|
+
usePullToRefresh
|
|
268
|
+
} from 'miragedev-sdk/mobile'
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
function MyComponent() {
|
|
273
|
+
const isOnline = useNetworkStatus()
|
|
274
|
+
const { canInstall, promptInstall } = useInstallPrompt()
|
|
275
|
+
const { permission, requestPermission } = useNotifications()
|
|
276
|
+
const { isRefreshing } = usePullToRefresh(async () => {
|
|
277
|
+
await fetchData()
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
// Your component logic
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## API Reference
|
|
285
|
+
|
|
286
|
+
Full API documentation with examples for every function is available in the code via JSDoc. Your AI assistant can read these to help you build faster.
|
|
287
|
+
|
|
288
|
+
## Examples
|
|
289
|
+
|
|
290
|
+
Check out the `examples/` directory for complete working applications:
|
|
291
|
+
|
|
292
|
+
- `examples/basic-saas` - Minimal SAAS with auth + billing
|
|
293
|
+
- `examples/with-biometric` - Biometric authentication example
|
|
294
|
+
- `examples/stripe-advanced` - Advanced billing with multiple tiers
|
|
295
|
+
|
|
296
|
+
## Troubleshooting
|
|
297
|
+
|
|
298
|
+
### "SDK not initialized" error
|
|
299
|
+
|
|
300
|
+
Make sure you call `initMirageDev()` before using any SDK functions. Import the initialization in your root layout.
|
|
301
|
+
|
|
302
|
+
### Webhooks not working
|
|
303
|
+
|
|
304
|
+
1. Verify your webhook secret is correct in `.env.local`
|
|
305
|
+
2. Make sure your webhook endpoint is publicly accessible
|
|
306
|
+
3. Check Stripe dashboard for webhook delivery logs
|
|
307
|
+
|
|
308
|
+
### TypeScript errors
|
|
309
|
+
|
|
310
|
+
The SDK is fully typed. If you see type errors, make sure you're using TypeScript 5.0+ and have `strict: true` in your tsconfig.json.
|
|
311
|
+
|
|
312
|
+
## Publishing the SDK
|
|
313
|
+
|
|
314
|
+
### For Maintainers: Automated Publishing
|
|
315
|
+
|
|
316
|
+
This SDK uses **automated versioning and publishing** via GitHub Actions.
|
|
317
|
+
|
|
318
|
+
#### How It Works
|
|
319
|
+
|
|
320
|
+
When a PR is merged to `main`:
|
|
321
|
+
1. ✅ Tests run automatically
|
|
322
|
+
2. ✅ Version is bumped based on commit messages:
|
|
323
|
+
- `feat:` → minor version (0.1.0 → 0.2.0)
|
|
324
|
+
- `fix:` → patch version (0.1.0 → 0.1.1)
|
|
325
|
+
- `feat!:` or `BREAKING CHANGE` → major version (0.1.0 → 1.0.0)
|
|
326
|
+
3. ✅ package.json is updated and committed
|
|
327
|
+
4. ✅ Git tag is created automatically
|
|
328
|
+
5. ✅ Package is published to NPM
|
|
329
|
+
6. ✅ GitHub Release is created
|
|
330
|
+
|
|
331
|
+
#### Setup (One Time)
|
|
332
|
+
|
|
333
|
+
1. Add `NPM_TOKEN` to GitHub repository secrets:
|
|
334
|
+
- Go to npmjs.com → Access Tokens → Generate New Token (Automation)
|
|
335
|
+
- Copy token
|
|
336
|
+
- Go to GitHub repo → Settings → Secrets → New secret
|
|
337
|
+
- Name: `NPM_TOKEN`, Value: (paste token)
|
|
338
|
+
|
|
339
|
+
2. That's it! Now every merge to main auto-publishes.
|
|
340
|
+
|
|
341
|
+
#### Publishing Process
|
|
342
|
+
|
|
343
|
+
**Simple workflow:**
|
|
344
|
+
```bash
|
|
345
|
+
# 1. Create feature branch
|
|
346
|
+
git checkout -b feat/new-feature
|
|
347
|
+
|
|
348
|
+
# 2. Make changes with conventional commits
|
|
349
|
+
git commit -m "feat: add new awesome feature"
|
|
350
|
+
|
|
351
|
+
# 3. Push and create PR
|
|
352
|
+
git push origin feat/new-feature
|
|
353
|
+
|
|
354
|
+
# 4. Merge PR to main
|
|
355
|
+
# → GitHub Actions automatically:
|
|
356
|
+
# - Runs tests
|
|
357
|
+
# - Bumps version (0.1.0 → 0.2.0)
|
|
358
|
+
# - Publishes to NPM
|
|
359
|
+
# - Creates release
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**No manual `npm version` or `npm publish` needed!**
|
|
363
|
+
|
|
364
|
+
#### Manual Publishing (Emergency Only)
|
|
365
|
+
|
|
366
|
+
If you need to publish manually:
|
|
367
|
+
```bash
|
|
368
|
+
npm version patch # or minor/major
|
|
369
|
+
npm run prepublishOnly # Runs type-check, tests, build
|
|
370
|
+
npm publish --access public
|
|
371
|
+
git push && git push --tags
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### After Publishing
|
|
375
|
+
|
|
376
|
+
Users can install the latest version:
|
|
377
|
+
```bash
|
|
378
|
+
npm install miragedev-sdk@latest
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## License
|
|
382
|
+
|
|
383
|
+
MIT © MirageDev
|
|
384
|
+
|
|
385
|
+
## Support
|
|
386
|
+
|
|
387
|
+
- 📖 [Documentation](https://github.com/miragedev/miragedev-sdk)
|
|
388
|
+
- 🐛 [Issue Tracker](https://github.com/miragedev/miragedev-sdk/issues)
|
|
389
|
+
- 💬 [Discussions](https://github.com/miragedev/miragedev-sdk/discussions)
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
Built with ❤️ for the Next.js community
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkBW4BLEIM_cjs = require('../chunk-BW4BLEIM.cjs');
|
|
4
|
+
require('../chunk-75ZPJI57.cjs');
|
|
5
|
+
|
|
6
|
+
// src/auth/biometric.ts
|
|
7
|
+
function isBiometricSupported() {
|
|
8
|
+
return typeof window !== "undefined" && window.PublicKeyCredential !== void 0 && typeof window.PublicKeyCredential === "function";
|
|
9
|
+
}
|
|
10
|
+
async function enableBiometric() {
|
|
11
|
+
if (!isBiometricSupported()) {
|
|
12
|
+
throw new chunkBW4BLEIM_cjs.MirageDevError(
|
|
13
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
14
|
+
"Biometric authentication is not supported in this browser"
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const optionsResponse = await fetch("/api/auth/biometric/register", {
|
|
19
|
+
method: "POST"
|
|
20
|
+
});
|
|
21
|
+
if (!optionsResponse.ok) {
|
|
22
|
+
throw new Error("Failed to get registration options");
|
|
23
|
+
}
|
|
24
|
+
const options = await optionsResponse.json();
|
|
25
|
+
const credential = await navigator.credentials.create({
|
|
26
|
+
publicKey: options
|
|
27
|
+
});
|
|
28
|
+
if (!credential) {
|
|
29
|
+
throw new Error("Failed to create credentials");
|
|
30
|
+
}
|
|
31
|
+
const registerResponse = await fetch("/api/auth/biometric/verify", {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify(credential)
|
|
35
|
+
});
|
|
36
|
+
if (!registerResponse.ok) {
|
|
37
|
+
throw new Error("Failed to register biometric");
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new chunkBW4BLEIM_cjs.MirageDevError(
|
|
41
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
42
|
+
`Failed to enable biometric authentication: ${error.message}`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function signInWithBiometric() {
|
|
47
|
+
if (!isBiometricSupported()) {
|
|
48
|
+
throw new chunkBW4BLEIM_cjs.MirageDevError(
|
|
49
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
50
|
+
"Biometric authentication is not supported in this browser"
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const optionsResponse = await fetch("/api/auth/biometric/authenticate");
|
|
55
|
+
if (!optionsResponse.ok) {
|
|
56
|
+
throw new Error("Failed to get authentication options");
|
|
57
|
+
}
|
|
58
|
+
const options = await optionsResponse.json();
|
|
59
|
+
const credential = await navigator.credentials.get({
|
|
60
|
+
publicKey: options
|
|
61
|
+
});
|
|
62
|
+
if (!credential) {
|
|
63
|
+
throw new Error("Failed to get credentials");
|
|
64
|
+
}
|
|
65
|
+
const verifyResponse = await fetch("/api/auth/biometric/verify", {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "Content-Type": "application/json" },
|
|
68
|
+
body: JSON.stringify(credential)
|
|
69
|
+
});
|
|
70
|
+
if (!verifyResponse.ok) {
|
|
71
|
+
throw new Error("Failed to verify biometric");
|
|
72
|
+
}
|
|
73
|
+
const session = await verifyResponse.json();
|
|
74
|
+
return session;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new chunkBW4BLEIM_cjs.MirageDevError(
|
|
77
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
78
|
+
`Biometric authentication failed: ${error.message}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
exports.enableBiometric = enableBiometric;
|
|
84
|
+
exports.isBiometricSupported = isBiometricSupported;
|
|
85
|
+
exports.signInWithBiometric = signInWithBiometric;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { S as Session } from '../auth-BC8JI28z.cjs';
|
|
2
|
+
|
|
3
|
+
declare function isBiometricSupported(): boolean;
|
|
4
|
+
declare function enableBiometric(): Promise<void>;
|
|
5
|
+
declare function signInWithBiometric(): Promise<Session>;
|
|
6
|
+
|
|
7
|
+
export { enableBiometric, isBiometricSupported, signInWithBiometric };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { S as Session } from '../auth-BC8JI28z.js';
|
|
2
|
+
|
|
3
|
+
declare function isBiometricSupported(): boolean;
|
|
4
|
+
declare function enableBiometric(): Promise<void>;
|
|
5
|
+
declare function signInWithBiometric(): Promise<Session>;
|
|
6
|
+
|
|
7
|
+
export { enableBiometric, isBiometricSupported, signInWithBiometric };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { MirageDevError } from '../chunk-JUTTFY3W.js';
|
|
2
|
+
import '../chunk-MLKGABMK.js';
|
|
3
|
+
|
|
4
|
+
// src/auth/biometric.ts
|
|
5
|
+
function isBiometricSupported() {
|
|
6
|
+
return typeof window !== "undefined" && window.PublicKeyCredential !== void 0 && typeof window.PublicKeyCredential === "function";
|
|
7
|
+
}
|
|
8
|
+
async function enableBiometric() {
|
|
9
|
+
if (!isBiometricSupported()) {
|
|
10
|
+
throw new MirageDevError(
|
|
11
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
12
|
+
"Biometric authentication is not supported in this browser"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const optionsResponse = await fetch("/api/auth/biometric/register", {
|
|
17
|
+
method: "POST"
|
|
18
|
+
});
|
|
19
|
+
if (!optionsResponse.ok) {
|
|
20
|
+
throw new Error("Failed to get registration options");
|
|
21
|
+
}
|
|
22
|
+
const options = await optionsResponse.json();
|
|
23
|
+
const credential = await navigator.credentials.create({
|
|
24
|
+
publicKey: options
|
|
25
|
+
});
|
|
26
|
+
if (!credential) {
|
|
27
|
+
throw new Error("Failed to create credentials");
|
|
28
|
+
}
|
|
29
|
+
const registerResponse = await fetch("/api/auth/biometric/verify", {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "Content-Type": "application/json" },
|
|
32
|
+
body: JSON.stringify(credential)
|
|
33
|
+
});
|
|
34
|
+
if (!registerResponse.ok) {
|
|
35
|
+
throw new Error("Failed to register biometric");
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new MirageDevError(
|
|
39
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
40
|
+
`Failed to enable biometric authentication: ${error.message}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function signInWithBiometric() {
|
|
45
|
+
if (!isBiometricSupported()) {
|
|
46
|
+
throw new MirageDevError(
|
|
47
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
48
|
+
"Biometric authentication is not supported in this browser"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const optionsResponse = await fetch("/api/auth/biometric/authenticate");
|
|
53
|
+
if (!optionsResponse.ok) {
|
|
54
|
+
throw new Error("Failed to get authentication options");
|
|
55
|
+
}
|
|
56
|
+
const options = await optionsResponse.json();
|
|
57
|
+
const credential = await navigator.credentials.get({
|
|
58
|
+
publicKey: options
|
|
59
|
+
});
|
|
60
|
+
if (!credential) {
|
|
61
|
+
throw new Error("Failed to get credentials");
|
|
62
|
+
}
|
|
63
|
+
const verifyResponse = await fetch("/api/auth/biometric/verify", {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { "Content-Type": "application/json" },
|
|
66
|
+
body: JSON.stringify(credential)
|
|
67
|
+
});
|
|
68
|
+
if (!verifyResponse.ok) {
|
|
69
|
+
throw new Error("Failed to verify biometric");
|
|
70
|
+
}
|
|
71
|
+
const session = await verifyResponse.json();
|
|
72
|
+
return session;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new MirageDevError(
|
|
75
|
+
"AUTH_INVALID_CREDENTIALS",
|
|
76
|
+
`Biometric authentication failed: ${error.message}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { enableBiometric, isBiometricSupported, signInWithBiometric };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('../chunk-75ZPJI57.cjs');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
function useSession() {
|
|
7
|
+
const [session, setSession] = react.useState(null);
|
|
8
|
+
const [status, setStatus] = react.useState("loading");
|
|
9
|
+
react.useEffect(() => {
|
|
10
|
+
fetch("/api/auth/session").then((res) => res.json()).then((data) => {
|
|
11
|
+
if (data && data.user) {
|
|
12
|
+
setSession(data);
|
|
13
|
+
setStatus("authenticated");
|
|
14
|
+
} else {
|
|
15
|
+
setSession(null);
|
|
16
|
+
setStatus("unauthenticated");
|
|
17
|
+
}
|
|
18
|
+
}).catch(() => {
|
|
19
|
+
setSession(null);
|
|
20
|
+
setStatus("unauthenticated");
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
return { session, status };
|
|
24
|
+
}
|
|
25
|
+
async function signIn(provider) {
|
|
26
|
+
const url = provider ? `/api/auth/signin/${provider}` : "/api/auth/signin";
|
|
27
|
+
if (typeof window !== "undefined") {
|
|
28
|
+
window.location.href = url;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function signOut() {
|
|
32
|
+
try {
|
|
33
|
+
await fetch("/api/auth/signout", { method: "POST" });
|
|
34
|
+
if (typeof window !== "undefined") {
|
|
35
|
+
window.location.href = "/";
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Sign out failed:", error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.signIn = signIn;
|
|
43
|
+
exports.signOut = signOut;
|
|
44
|
+
exports.useSession = useSession;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { S as Session } from '../auth-BC8JI28z.cjs';
|
|
2
|
+
|
|
3
|
+
type SessionStatus = 'authenticated' | 'unauthenticated' | 'loading';
|
|
4
|
+
interface UseSessionReturn {
|
|
5
|
+
session: Session | null;
|
|
6
|
+
status: SessionStatus;
|
|
7
|
+
}
|
|
8
|
+
declare function useSession(): UseSessionReturn;
|
|
9
|
+
declare function signIn(provider?: string): Promise<void>;
|
|
10
|
+
declare function signOut(): Promise<void>;
|
|
11
|
+
|
|
12
|
+
export { type SessionStatus, type UseSessionReturn, signIn, signOut, useSession };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { S as Session } from '../auth-BC8JI28z.js';
|
|
2
|
+
|
|
3
|
+
type SessionStatus = 'authenticated' | 'unauthenticated' | 'loading';
|
|
4
|
+
interface UseSessionReturn {
|
|
5
|
+
session: Session | null;
|
|
6
|
+
status: SessionStatus;
|
|
7
|
+
}
|
|
8
|
+
declare function useSession(): UseSessionReturn;
|
|
9
|
+
declare function signIn(provider?: string): Promise<void>;
|
|
10
|
+
declare function signOut(): Promise<void>;
|
|
11
|
+
|
|
12
|
+
export { type SessionStatus, type UseSessionReturn, signIn, signOut, useSession };
|