@authon/svelte 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +22 -113
- package/README.md +116 -376
- package/dist/index.cjs.map +1 -1
- package/package.json +6 -3
- package/src/components/SignIn.svelte +39 -0
- package/src/components/SignUp.svelte +39 -0
package/README.ko.md
CHANGED
|
@@ -2,140 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
# @authon/svelte
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Svelte 인증 -- 반응형 스토어 -- 셀프 호스팅 Clerk 대안
|
|
6
6
|
|
|
7
7
|
## 설치
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install @authon/svelte
|
|
11
|
-
# 또는
|
|
12
|
-
pnpm add @authon/svelte
|
|
13
11
|
```
|
|
14
12
|
|
|
15
|
-
`svelte >= 4.0.0`이 필요합니다.
|
|
16
|
-
|
|
17
13
|
## 빠른 시작
|
|
18
14
|
|
|
19
|
-
### 1. 초기화
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
// src/lib/authon.ts
|
|
23
|
-
import { initAuthon } from '@authon/svelte';
|
|
24
|
-
|
|
25
|
-
export const authon = initAuthon({
|
|
26
|
-
publishableKey: 'pk_live_...',
|
|
27
|
-
});
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 2. Store 사용
|
|
31
|
-
|
|
32
15
|
```svelte
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
import {
|
|
16
|
+
<!-- +layout.svelte -->
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { initAuthon } from '@authon/svelte';
|
|
19
|
+
import { onDestroy } from 'svelte';
|
|
20
|
+
const authon = initAuthon('pk_live_...', { apiUrl: 'https://your-authon-server.com' });
|
|
21
|
+
onDestroy(() => authon.destroy());
|
|
36
22
|
</script>
|
|
37
|
-
|
|
38
|
-
{#if $isLoading}
|
|
39
|
-
<p>Loading...</p>
|
|
40
|
-
{:else if $isSignedIn}
|
|
41
|
-
<p>Welcome, {$user?.displayName}</p>
|
|
42
|
-
<button on:click={signOut}>Sign Out</button>
|
|
43
|
-
{:else}
|
|
44
|
-
<button on:click={openSignIn}>Sign In</button>
|
|
45
|
-
{/if}
|
|
23
|
+
<slot />
|
|
46
24
|
```
|
|
47
25
|
|
|
48
|
-
### 3. 컴포넌트 사용
|
|
49
|
-
|
|
50
26
|
```svelte
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</script>
|
|
54
|
-
|
|
55
|
-
<SignedIn>
|
|
56
|
-
<UserButton />
|
|
57
|
-
</SignedIn>
|
|
58
|
-
<SignedOut>
|
|
59
|
-
<button on:click={openSignIn}>Sign In</button>
|
|
60
|
-
</SignedOut>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## API 레퍼런스
|
|
64
|
-
|
|
65
|
-
### Store
|
|
66
|
-
|
|
67
|
-
| Store | 타입 | 설명 |
|
|
68
|
-
|-------|------|------|
|
|
69
|
-
| `user` | `Readable<AuthonUser \| null>` | 현재 사용자 |
|
|
70
|
-
| `isSignedIn` | `Readable<boolean>` | 로그인 여부 |
|
|
71
|
-
| `isLoading` | `Readable<boolean>` | 인증 상태 로딩 여부 |
|
|
72
|
-
|
|
73
|
-
### 액션
|
|
74
|
-
|
|
75
|
-
| 함수 | 반환값 | 설명 |
|
|
76
|
-
|------|--------|------|
|
|
77
|
-
| `openSignIn()` | `Promise<void>` | 로그인 모달 열기 |
|
|
78
|
-
| `openSignUp()` | `Promise<void>` | 회원가입 모달 열기 |
|
|
79
|
-
| `signOut()` | `Promise<void>` | 로그아웃 |
|
|
80
|
-
| `getToken()` | `string \| null` | 현재 액세스 토큰 반환 |
|
|
81
|
-
|
|
82
|
-
### 컴포넌트
|
|
83
|
-
|
|
84
|
-
| 컴포넌트 | 설명 |
|
|
85
|
-
|----------|------|
|
|
86
|
-
| `<SignedIn>` | 로그인 상태일 때만 슬롯 렌더링 |
|
|
87
|
-
| `<SignedOut>` | 로그아웃 상태일 때만 슬롯 렌더링 |
|
|
88
|
-
| `<UserButton>` | 로그아웃 기능이 포함된 아바타 드롭다운 |
|
|
89
|
-
|
|
90
|
-
## 다중 인증 (MFA)
|
|
91
|
-
|
|
92
|
-
Authon 클라이언트 인스턴스를 통해 MFA에 접근합니다.
|
|
93
|
-
|
|
94
|
-
```svelte
|
|
95
|
-
<script>
|
|
27
|
+
<!-- +page.svelte -->
|
|
28
|
+
<script lang="ts">
|
|
96
29
|
import { getAuthon } from '@authon/svelte';
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const authon = getAuthon();
|
|
100
|
-
let qrSvg = '';
|
|
101
|
-
let mfaToken = '';
|
|
102
|
-
|
|
103
|
-
async function enableMfa() {
|
|
104
|
-
const setup = await authon.client.setupMfa();
|
|
105
|
-
qrSvg = setup.qrCodeSvg; // Display QR for authenticator app
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async function verifySetup(code) {
|
|
109
|
-
await authon.client.verifyMfaSetup(code);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function signIn(email, password) {
|
|
113
|
-
try {
|
|
114
|
-
await authon.client.signInWithEmail(email, password);
|
|
115
|
-
} catch (err) {
|
|
116
|
-
if (err instanceof AuthonMfaRequiredError) {
|
|
117
|
-
mfaToken = err.mfaToken; // Show TOTP input
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async function verifyMfa(code) {
|
|
123
|
-
await authon.client.verifyMfa(mfaToken, code);
|
|
124
|
-
}
|
|
30
|
+
const { user, isSignedIn, openSignIn, signOut } = getAuthon();
|
|
125
31
|
</script>
|
|
126
32
|
|
|
127
|
-
{#if
|
|
128
|
-
{
|
|
129
|
-
<
|
|
33
|
+
{#if $isSignedIn}
|
|
34
|
+
<p>환영합니다, {$user?.displayName}</p>
|
|
35
|
+
<button on:click={signOut}>로그아웃</button>
|
|
36
|
+
{:else}
|
|
37
|
+
<button on:click={openSignIn}>로그인</button>
|
|
130
38
|
{/if}
|
|
131
39
|
```
|
|
132
40
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
## 문서
|
|
41
|
+
## 환경 변수
|
|
136
42
|
|
|
137
|
-
|
|
43
|
+
| 변수 | 필수 | 설명 |
|
|
44
|
+
|------|------|------|
|
|
45
|
+
| `PUBLIC_AUTHON_API_URL` | Yes | Authon 서버 URL |
|
|
46
|
+
| `PUBLIC_AUTHON_PUBLISHABLE_KEY` | Yes | 퍼블리셔블 키 |
|
|
138
47
|
|
|
139
48
|
## 라이선스
|
|
140
49
|
|
|
141
|
-
|
|
50
|
+
MIT
|
package/README.md
CHANGED
|
@@ -2,45 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
# @authon/svelte
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Drop-in Svelte authentication with reactive stores — self-hosted Clerk alternative, Auth0 alternative
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@authon/svelte)
|
|
8
|
+
[](../../LICENSE)
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
Before installing the SDK, create an Authon project and get your API keys:
|
|
13
|
+
|
|
14
|
+
1. **Create a project** at [Authon Dashboard](https://authon.dev/dashboard/overview)
|
|
15
|
+
- Click "Create Project" and enter your app name
|
|
16
|
+
- Select the authentication methods you want (Email/Password, OAuth providers, etc.)
|
|
17
|
+
|
|
18
|
+
2. **Get your API keys** from Project Settings → API Keys
|
|
19
|
+
- **Publishable Key** (`pk_live_...` or `pk_test_...`) — safe to use in client-side code
|
|
20
|
+
- **Secret Key** (`sk_live_...` or `sk_test_...`) — server-side only, never expose to clients
|
|
21
|
+
|
|
22
|
+
3. **Configure OAuth providers** (optional) in Project Settings → OAuth
|
|
23
|
+
- Add Google, Apple, GitHub, etc. with their respective Client ID and Secret
|
|
24
|
+
- Set the redirect URL to `https://api.authon.dev/v1/auth/oauth/redirect`
|
|
25
|
+
|
|
26
|
+
> **Test vs Live keys:** Use `pk_test_...` during development. Switch to `pk_live_...` before deploying to production. Test keys use a sandbox environment with no rate limits.
|
|
6
27
|
|
|
7
28
|
## Install
|
|
8
29
|
|
|
9
30
|
```bash
|
|
10
|
-
npm install @authon/svelte
|
|
31
|
+
npm install @authon/svelte
|
|
11
32
|
```
|
|
12
33
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Setup
|
|
16
|
-
|
|
17
|
-
Initialize Authon in your root layout component and provide it to the component tree via Svelte context:
|
|
34
|
+
## Quick Start
|
|
18
35
|
|
|
19
36
|
```svelte
|
|
20
37
|
<!-- src/routes/+layout.svelte -->
|
|
21
38
|
<script lang="ts">
|
|
22
|
-
import { initAuthon } from '@authon/svelte'
|
|
23
|
-
import { onDestroy } from 'svelte'
|
|
39
|
+
import { initAuthon } from '@authon/svelte';
|
|
40
|
+
import { onDestroy } from 'svelte';
|
|
24
41
|
|
|
25
|
-
const authon = initAuthon('
|
|
42
|
+
const authon = initAuthon('pk_live_YOUR_PUBLISHABLE_KEY', {
|
|
43
|
+
apiUrl: 'https://your-authon-server.com',
|
|
26
44
|
theme: 'auto',
|
|
27
|
-
|
|
28
|
-
})
|
|
45
|
+
});
|
|
29
46
|
|
|
30
|
-
onDestroy(() => authon.destroy())
|
|
47
|
+
onDestroy(() => authon.destroy());
|
|
31
48
|
</script>
|
|
32
49
|
|
|
33
50
|
<slot />
|
|
34
51
|
```
|
|
35
52
|
|
|
36
|
-
Then access the store in any child component:
|
|
37
|
-
|
|
38
53
|
```svelte
|
|
39
54
|
<!-- src/routes/+page.svelte -->
|
|
40
55
|
<script lang="ts">
|
|
41
|
-
import { getAuthon } from '@authon/svelte'
|
|
42
|
-
|
|
43
|
-
const { user, isSignedIn, isLoading, openSignIn, signOut } = getAuthon()
|
|
56
|
+
import { getAuthon } from '@authon/svelte';
|
|
57
|
+
const { user, isSignedIn, isLoading, openSignIn, signOut } = getAuthon();
|
|
44
58
|
</script>
|
|
45
59
|
|
|
46
60
|
{#if $isLoading}
|
|
@@ -53,412 +67,138 @@ Then access the store in any child component:
|
|
|
53
67
|
{/if}
|
|
54
68
|
```
|
|
55
69
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
### `initAuthon(publishableKey, config?)`
|
|
59
|
-
|
|
60
|
-
Creates an `AuthonStore` and registers it in Svelte context. Call this once in your root layout.
|
|
61
|
-
|
|
62
|
-
```ts
|
|
63
|
-
import { initAuthon } from '@authon/svelte'
|
|
64
|
-
|
|
65
|
-
const authon = initAuthon('pk_live_...', {
|
|
66
|
-
theme: 'auto',
|
|
67
|
-
locale: 'en',
|
|
68
|
-
})
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### `getAuthon()`
|
|
70
|
+
## Common Tasks
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
import { getAuthon } from '@authon/svelte'
|
|
77
|
-
|
|
78
|
-
const authon = getAuthon()
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### `createAuthonStore(publishableKey, config?)`
|
|
82
|
-
|
|
83
|
-
Low-level store factory. Use `initAuthon` / `getAuthon` for most cases; use this directly if you need a store without Svelte context.
|
|
84
|
-
|
|
85
|
-
### `AuthonStore`
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
interface AuthonStore {
|
|
89
|
-
user: Readable<AuthonUser | null>
|
|
90
|
-
isSignedIn: Readable<boolean>
|
|
91
|
-
isLoading: Readable<boolean>
|
|
92
|
-
client: Authon // @authon/js Authon instance
|
|
93
|
-
signOut: () => Promise<void>
|
|
94
|
-
openSignIn: () => Promise<void>
|
|
95
|
-
openSignUp: () => Promise<void>
|
|
96
|
-
getToken: () => string | null
|
|
97
|
-
destroy: () => void
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
All store values are Svelte `Readable` stores — subscribe with the `$` prefix in templates.
|
|
102
|
-
|
|
103
|
-
### `renderSocialButtons(options)`
|
|
104
|
-
|
|
105
|
-
Renders branded OAuth provider buttons into a DOM element. Returns a cleanup function.
|
|
106
|
-
|
|
107
|
-
**Options:**
|
|
108
|
-
|
|
109
|
-
| Option | Type | Default | Description |
|
|
110
|
-
|---|---|---|---|
|
|
111
|
-
| `client` | `Authon` | required | Authon client instance |
|
|
112
|
-
| `container` | `HTMLElement` | required | Target DOM element |
|
|
113
|
-
| `onSuccess` | `() => void` | — | Called after successful OAuth sign-in |
|
|
114
|
-
| `onError` | `(error: Error) => void` | — | Called on OAuth error |
|
|
115
|
-
| `compact` | `boolean` | `false` | Icon-only square buttons in a row |
|
|
116
|
-
| `gap` | `number` | `10` / `12` | Gap between buttons in px |
|
|
117
|
-
| `labels` | `Record<provider, string>` | — | Override button labels per provider |
|
|
118
|
-
| `borderRadius` | `number` | `10` | Button border radius in px |
|
|
119
|
-
| `height` | `number` | `48` | Button height in px |
|
|
120
|
-
| `size` | `number` | `48` | Icon button size in px (compact mode) |
|
|
121
|
-
|
|
122
|
-
## Examples
|
|
123
|
-
|
|
124
|
-
### Basic auth state
|
|
72
|
+
### Add Google OAuth Login
|
|
125
73
|
|
|
126
74
|
```svelte
|
|
127
75
|
<script lang="ts">
|
|
128
|
-
import { getAuthon } from '@authon/svelte'
|
|
129
|
-
|
|
130
|
-
const { user, isSignedIn, isLoading, openSignIn, signOut } = getAuthon()
|
|
76
|
+
import { getAuthon } from '@authon/svelte';
|
|
77
|
+
const { client } = getAuthon();
|
|
131
78
|
</script>
|
|
132
79
|
|
|
133
|
-
{
|
|
134
|
-
<p>Loading...</p>
|
|
135
|
-
{:else if $isSignedIn}
|
|
136
|
-
<p>Hello, {$user?.displayName ?? $user?.email}</p>
|
|
137
|
-
<button on:click={signOut}>Sign out</button>
|
|
138
|
-
{:else}
|
|
139
|
-
<button on:click={openSignIn}>Sign in</button>
|
|
140
|
-
{/if}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Email + password sign-in
|
|
144
|
-
|
|
145
|
-
```svelte
|
|
146
|
-
<script lang="ts">
|
|
147
|
-
import { getAuthon } from '@authon/svelte'
|
|
148
|
-
|
|
149
|
-
const { client } = getAuthon()
|
|
150
|
-
|
|
151
|
-
let email = ''
|
|
152
|
-
let password = ''
|
|
153
|
-
let loading = false
|
|
154
|
-
let error = ''
|
|
155
|
-
|
|
156
|
-
async function handleSignIn() {
|
|
157
|
-
loading = true
|
|
158
|
-
error = ''
|
|
159
|
-
try {
|
|
160
|
-
await client.signInWithEmail(email, password)
|
|
161
|
-
} catch (e: any) {
|
|
162
|
-
error = e.message
|
|
163
|
-
} finally {
|
|
164
|
-
loading = false
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
</script>
|
|
168
|
-
|
|
169
|
-
<form on:submit|preventDefault={handleSignIn}>
|
|
170
|
-
<input bind:value={email} type="email" placeholder="Email" />
|
|
171
|
-
<input bind:value={password} type="password" placeholder="Password" />
|
|
172
|
-
<button type="submit" disabled={loading}>Sign in</button>
|
|
173
|
-
{#if error}<p>{error}</p>{/if}
|
|
174
|
-
</form>
|
|
80
|
+
<button on:click={() => client.signInWithOAuth('google')}>Sign in with Google</button>
|
|
175
81
|
```
|
|
176
82
|
|
|
177
|
-
###
|
|
83
|
+
### Protect a Route
|
|
178
84
|
|
|
179
85
|
```svelte
|
|
86
|
+
<!-- src/routes/dashboard/+page.svelte -->
|
|
180
87
|
<script lang="ts">
|
|
181
|
-
import { getAuthon
|
|
182
|
-
import {
|
|
88
|
+
import { getAuthon } from '@authon/svelte';
|
|
89
|
+
import { goto } from '$app/navigation';
|
|
90
|
+
import { onMount } from 'svelte';
|
|
183
91
|
|
|
184
|
-
const {
|
|
185
|
-
let container: HTMLElement
|
|
186
|
-
let cleanup: (() => void) | undefined
|
|
92
|
+
const { isSignedIn, isLoading } = getAuthon();
|
|
187
93
|
|
|
188
94
|
onMount(() => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
container,
|
|
192
|
-
onSuccess: () => window.location.href = '/dashboard',
|
|
193
|
-
onError: (e) => console.error(e),
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
onDestroy(() => cleanup?.())
|
|
198
|
-
|
|
199
|
-
// Or trigger a single provider directly
|
|
200
|
-
async function signInWithGoogle() {
|
|
201
|
-
await client.signInWithOAuth('google')
|
|
202
|
-
}
|
|
203
|
-
</script>
|
|
204
|
-
|
|
205
|
-
<div bind:this={container} />
|
|
206
|
-
<button on:click={signInWithGoogle}>Sign in with Google</button>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### MFA setup
|
|
210
|
-
|
|
211
|
-
```svelte
|
|
212
|
-
<script lang="ts">
|
|
213
|
-
import { getAuthon } from '@authon/svelte'
|
|
214
|
-
|
|
215
|
-
const { client } = getAuthon()
|
|
216
|
-
|
|
217
|
-
let qrCodeSvg = ''
|
|
218
|
-
let secret = ''
|
|
219
|
-
let backupCodes: string[] = []
|
|
220
|
-
let verifyCode = ''
|
|
221
|
-
|
|
222
|
-
async function initMfaSetup() {
|
|
223
|
-
const res = await client.setupMfa()
|
|
224
|
-
qrCodeSvg = res.qrCodeSvg // SVG string for display
|
|
225
|
-
secret = res.secret
|
|
226
|
-
backupCodes = res.backupCodes
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function confirmSetup() {
|
|
230
|
-
await client.verifyMfaSetup(verifyCode)
|
|
231
|
-
alert('MFA enabled')
|
|
232
|
-
}
|
|
95
|
+
if (!$isLoading && !$isSignedIn) goto('/sign-in');
|
|
96
|
+
});
|
|
233
97
|
</script>
|
|
234
98
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
{#if qrCodeSvg}
|
|
238
|
-
{@html qrCodeSvg}
|
|
239
|
-
<p>Scan with your authenticator app</p>
|
|
240
|
-
<p>Secret: {secret}</p>
|
|
241
|
-
<ul>{#each backupCodes as code}<li>{code}</li>{/each}</ul>
|
|
242
|
-
<input bind:value={verifyCode} placeholder="6-digit code" />
|
|
243
|
-
<button on:click={confirmSetup}>Verify</button>
|
|
99
|
+
{#if $isSignedIn}
|
|
100
|
+
<h1>Dashboard</h1>
|
|
244
101
|
{/if}
|
|
245
102
|
```
|
|
246
103
|
|
|
247
|
-
###
|
|
248
|
-
|
|
249
|
-
```svelte
|
|
250
|
-
<script lang="ts">
|
|
251
|
-
import { getAuthon } from '@authon/svelte'
|
|
252
|
-
import { AuthonMfaRequiredError } from '@authon/js'
|
|
253
|
-
|
|
254
|
-
const { client } = getAuthon()
|
|
255
|
-
|
|
256
|
-
let mfaToken = ''
|
|
257
|
-
let totpCode = ''
|
|
258
|
-
|
|
259
|
-
async function signIn(email: string, password: string) {
|
|
260
|
-
try {
|
|
261
|
-
await client.signInWithEmail(email, password)
|
|
262
|
-
} catch (e) {
|
|
263
|
-
if (e instanceof AuthonMfaRequiredError) {
|
|
264
|
-
mfaToken = e.mfaToken // show TOTP input
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
async function verifyMfa() {
|
|
270
|
-
await client.verifyMfa(mfaToken, totpCode)
|
|
271
|
-
}
|
|
272
|
-
</script>
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### Passwordless — magic link
|
|
104
|
+
### Get Current User
|
|
276
105
|
|
|
277
106
|
```svelte
|
|
278
107
|
<script lang="ts">
|
|
279
|
-
import { getAuthon } from '@authon/svelte'
|
|
280
|
-
|
|
281
|
-
const { client } = getAuthon()
|
|
282
|
-
let email = ''
|
|
283
|
-
let sent = false
|
|
284
|
-
|
|
285
|
-
async function sendMagicLink() {
|
|
286
|
-
await client.sendMagicLink(email)
|
|
287
|
-
sent = true
|
|
288
|
-
}
|
|
108
|
+
import { getAuthon } from '@authon/svelte';
|
|
109
|
+
const { user, isLoading } = getAuthon();
|
|
289
110
|
</script>
|
|
290
111
|
|
|
291
|
-
{#if
|
|
292
|
-
<p>
|
|
112
|
+
{#if $isLoading}
|
|
113
|
+
<p>Loading...</p>
|
|
114
|
+
{:else if $user}
|
|
115
|
+
<p>Email: {$user.email}</p>
|
|
116
|
+
<p>Name: {$user.displayName}</p>
|
|
293
117
|
{:else}
|
|
294
|
-
<
|
|
295
|
-
<button on:click={sendMagicLink}>Send magic link</button>
|
|
118
|
+
<p>Not signed in</p>
|
|
296
119
|
{/if}
|
|
297
120
|
```
|
|
298
121
|
|
|
299
|
-
###
|
|
122
|
+
### Add Email/Password Auth
|
|
300
123
|
|
|
301
124
|
```svelte
|
|
302
125
|
<script lang="ts">
|
|
303
|
-
import { getAuthon } from '@authon/svelte'
|
|
126
|
+
import { getAuthon } from '@authon/svelte';
|
|
127
|
+
const { client } = getAuthon();
|
|
128
|
+
let email = '';
|
|
129
|
+
let password = '';
|
|
304
130
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
let otp = ''
|
|
308
|
-
let step: 'email' | 'verify' = 'email'
|
|
309
|
-
|
|
310
|
-
async function sendOtp() {
|
|
311
|
-
await client.sendEmailOtp(email)
|
|
312
|
-
step = 'verify'
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
async function verifyOtp() {
|
|
316
|
-
const user = await client.verifyPasswordless({ email, code: otp })
|
|
317
|
-
console.log('Signed in as:', user.email)
|
|
131
|
+
async function handleSignIn() {
|
|
132
|
+
await client.signInWithEmail(email, password);
|
|
318
133
|
}
|
|
319
134
|
</script>
|
|
320
135
|
|
|
321
|
-
{
|
|
136
|
+
<form on:submit|preventDefault={handleSignIn}>
|
|
322
137
|
<input bind:value={email} type="email" placeholder="Email" />
|
|
323
|
-
<
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
<button on:click={verifyOtp}>Verify</button>
|
|
327
|
-
{/if}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### Passkeys
|
|
331
|
-
|
|
332
|
-
```svelte
|
|
333
|
-
<script lang="ts">
|
|
334
|
-
import { getAuthon } from '@authon/svelte'
|
|
335
|
-
|
|
336
|
-
const { client } = getAuthon()
|
|
337
|
-
|
|
338
|
-
// Register (user must be signed in)
|
|
339
|
-
async function registerPasskey() {
|
|
340
|
-
const credential = await client.registerPasskey('My Device')
|
|
341
|
-
console.log('Registered:', credential.id)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Authenticate
|
|
345
|
-
async function loginWithPasskey() {
|
|
346
|
-
const user = await client.authenticateWithPasskey()
|
|
347
|
-
console.log('Signed in as:', user.email)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// List registered passkeys
|
|
351
|
-
async function listPasskeys() {
|
|
352
|
-
const keys = await client.listPasskeys()
|
|
353
|
-
console.log(keys)
|
|
354
|
-
}
|
|
355
|
-
</script>
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### Web3 wallet authentication
|
|
359
|
-
|
|
360
|
-
```svelte
|
|
361
|
-
<script lang="ts">
|
|
362
|
-
import { getAuthon } from '@authon/svelte'
|
|
363
|
-
|
|
364
|
-
const { client } = getAuthon()
|
|
365
|
-
|
|
366
|
-
async function signInWithWallet() {
|
|
367
|
-
const address = '0xYourWalletAddress'
|
|
368
|
-
|
|
369
|
-
// 1. Get a nonce + signable message from Authon
|
|
370
|
-
const { nonce, message } = await client.web3GetNonce(address, 'evm', 'metamask')
|
|
371
|
-
|
|
372
|
-
// 2. Sign the message with the wallet
|
|
373
|
-
const signature = await window.ethereum.request({
|
|
374
|
-
method: 'personal_sign',
|
|
375
|
-
params: [message, address],
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
// 3. Verify the signature and sign in
|
|
379
|
-
const user = await client.web3Verify(message, signature, address, 'evm', 'metamask')
|
|
380
|
-
console.log('Signed in as:', user.email)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async function listLinkedWallets() {
|
|
384
|
-
const wallets = await client.listWallets()
|
|
385
|
-
console.log(wallets)
|
|
386
|
-
}
|
|
387
|
-
</script>
|
|
138
|
+
<input bind:value={password} type="password" placeholder="Password" />
|
|
139
|
+
<button type="submit">Sign in</button>
|
|
140
|
+
</form>
|
|
388
141
|
```
|
|
389
142
|
|
|
390
|
-
###
|
|
143
|
+
### Handle Sign Out
|
|
391
144
|
|
|
392
145
|
```svelte
|
|
393
146
|
<script lang="ts">
|
|
394
|
-
import { getAuthon } from '@authon/svelte'
|
|
395
|
-
|
|
396
|
-
const { client } = getAuthon()
|
|
397
|
-
|
|
398
|
-
async function saveProfile() {
|
|
399
|
-
const updated = await client.updateProfile({
|
|
400
|
-
displayName: 'Jane Doe',
|
|
401
|
-
avatarUrl: 'https://example.com/avatar.png',
|
|
402
|
-
phone: '+1234567890',
|
|
403
|
-
publicMetadata: { role: 'admin' },
|
|
404
|
-
})
|
|
405
|
-
console.log('Updated user:', updated)
|
|
406
|
-
}
|
|
147
|
+
import { getAuthon } from '@authon/svelte';
|
|
148
|
+
const { signOut } = getAuthon();
|
|
407
149
|
</script>
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### Session management
|
|
411
|
-
|
|
412
|
-
```svelte
|
|
413
|
-
<script lang="ts">
|
|
414
|
-
import { getAuthon } from '@authon/svelte'
|
|
415
|
-
import { onMount } from 'svelte'
|
|
416
|
-
import type { SessionInfo } from '@authon/shared'
|
|
417
|
-
|
|
418
|
-
const { client } = getAuthon()
|
|
419
|
-
let sessions: SessionInfo[] = []
|
|
420
150
|
|
|
421
|
-
|
|
422
|
-
sessions = await client.listSessions()
|
|
423
|
-
})
|
|
424
|
-
|
|
425
|
-
async function revokeSession(sessionId: string) {
|
|
426
|
-
await client.revokeSession(sessionId)
|
|
427
|
-
sessions = sessions.filter(s => s.id !== sessionId)
|
|
428
|
-
}
|
|
429
|
-
</script>
|
|
430
|
-
|
|
431
|
-
<ul>
|
|
432
|
-
{#each sessions as session (session.id)}
|
|
433
|
-
<li>
|
|
434
|
-
{session.userAgent} — {session.createdAt}
|
|
435
|
-
<button on:click={() => revokeSession(session.id)}>Revoke</button>
|
|
436
|
-
</li>
|
|
437
|
-
{/each}
|
|
438
|
-
</ul>
|
|
151
|
+
<button on:click={signOut}>Sign Out</button>
|
|
439
152
|
```
|
|
440
153
|
|
|
441
|
-
##
|
|
154
|
+
## Environment Variables
|
|
442
155
|
|
|
443
|
-
|
|
|
444
|
-
|
|
445
|
-
| `
|
|
446
|
-
| `
|
|
447
|
-
| `config.locale` | `string` | `'en'` | Language code |
|
|
448
|
-
| `config.apiUrl` | `string` | `'https://api.authon.dev'` | Custom API base URL |
|
|
449
|
-
| `config.appearance` | `Partial<BrandingConfig>` | — | Override branding colors and logo |
|
|
156
|
+
| Variable | Required | Description |
|
|
157
|
+
|----------|----------|-------------|
|
|
158
|
+
| `PUBLIC_AUTHON_API_URL` | Yes | Your Authon server URL |
|
|
159
|
+
| `PUBLIC_AUTHON_PUBLISHABLE_KEY` | Yes | Project publishable key |
|
|
450
160
|
|
|
451
|
-
##
|
|
452
|
-
|
|
453
|
-
```ts
|
|
454
|
-
import type { AuthonStore, SocialButtonsOptions } from '@authon/svelte'
|
|
455
|
-
import type { AuthonUser, SessionInfo, PasskeyCredential, Web3Wallet } from '@authon/shared'
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
## Documentation
|
|
161
|
+
## API Reference
|
|
459
162
|
|
|
460
|
-
|
|
163
|
+
### Setup
|
|
164
|
+
|
|
165
|
+
| Function | Description |
|
|
166
|
+
|----------|-------------|
|
|
167
|
+
| `initAuthon(key, config?)` | Create store and set in Svelte context (call in root layout) |
|
|
168
|
+
| `getAuthon()` | Get `AuthonStore` from context (call in child components) |
|
|
169
|
+
| `createAuthonStore(key, config?)` | Low-level store factory (without context) |
|
|
170
|
+
|
|
171
|
+
### AuthonStore
|
|
172
|
+
|
|
173
|
+
| Property / Method | Type |
|
|
174
|
+
|-------------------|------|
|
|
175
|
+
| `user` | `Readable<AuthonUser \| null>` |
|
|
176
|
+
| `isSignedIn` | `Readable<boolean>` |
|
|
177
|
+
| `isLoading` | `Readable<boolean>` |
|
|
178
|
+
| `client` | `Authon` |
|
|
179
|
+
| `signOut()` | `Promise<void>` |
|
|
180
|
+
| `openSignIn()` | `Promise<void>` |
|
|
181
|
+
| `openSignUp()` | `Promise<void>` |
|
|
182
|
+
| `getToken()` | `string \| null` |
|
|
183
|
+
| `web3GetNonce(...)` | Web3 nonce request |
|
|
184
|
+
| `web3Verify(...)` | Web3 sign-in |
|
|
185
|
+
| `passwordlessSendCode(...)` | Send magic link or OTP |
|
|
186
|
+
| `passwordlessVerifyCode(...)` | Verify OTP |
|
|
187
|
+
| `passkeyRegister(...)` | Register passkey |
|
|
188
|
+
| `passkeyAuthenticate(...)` | Auth with passkey |
|
|
189
|
+
| `destroy()` | Cleanup |
|
|
190
|
+
|
|
191
|
+
## Comparison
|
|
192
|
+
|
|
193
|
+
| Feature | Authon | Clerk | Auth.js |
|
|
194
|
+
|---------|--------|-------|---------|
|
|
195
|
+
| Self-hosted | Yes | No | Partial |
|
|
196
|
+
| Pricing | Free | $25/mo+ | Free |
|
|
197
|
+
| OAuth providers | 10+ | 20+ | 80+ |
|
|
198
|
+
| ShadowDOM modal | Yes | No | No |
|
|
199
|
+
| MFA/Passkeys | Yes | Yes | Plugin |
|
|
200
|
+
| Web3 auth | Yes | No | No |
|
|
461
201
|
|
|
462
202
|
## License
|
|
463
203
|
|
|
464
|
-
|
|
204
|
+
MIT
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/store.ts","../src/context.ts","../src/SocialButtons.ts"],"sourcesContent":["export { createAuthonStore } from './store';\nexport type { AuthonStore } from './store';\nexport { initAuthon, getAuthon } from './context';\nexport { renderSocialButtons } from './SocialButtons';\nexport type { SocialButtonsOptions } from './SocialButtons';\nexport type {\n PasskeyCredential,\n Web3Chain,\n Web3NonceResponse,\n Web3Wallet,\n Web3WalletType,\n} from '@authon/shared';\n","import { writable, derived, type Readable } from 'svelte/store';\nimport { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type {\n AuthonUser,\n PasskeyCredential,\n Web3Chain,\n Web3NonceResponse,\n Web3Wallet,\n Web3WalletType,\n} from '@authon/shared';\n\nexport interface AuthonStore {\n user: Readable<AuthonUser | null>;\n isSignedIn: Readable<boolean>;\n isLoading: Readable<boolean>;\n signOut: () => Promise<void>;\n openSignIn: () => Promise<void>;\n openSignUp: () => Promise<void>;\n getToken: () => string | null;\n destroy: () => void;\n client: Authon;\n // Web3\n web3GetNonce: (address: string, chain: Web3Chain, walletType: Web3WalletType, chainId?: number) => Promise<Web3NonceResponse>;\n web3Verify: (message: string, signature: string, address: string, chain: Web3Chain, walletType: Web3WalletType) => Promise<AuthonUser>;\n web3LinkWallet: (params: { address: string; chain: Web3Chain; walletType: Web3WalletType; chainId?: number; message: string; signature: string }) => Promise<Web3Wallet>;\n web3UnlinkWallet: (walletId: string) => Promise<void>;\n web3GetWallets: () => Promise<Web3Wallet[]>;\n // Passwordless\n passwordlessSendCode: (email: string, type?: 'magic-link' | 'otp') => Promise<void>;\n passwordlessVerifyCode: (email: string, code: string) => Promise<AuthonUser>;\n // Passkeys\n passkeyRegister: (name?: string) => Promise<PasskeyCredential>;\n passkeyAuthenticate: (email?: string) => Promise<AuthonUser>;\n passkeyList: () => Promise<PasskeyCredential[]>;\n passkeyDelete: (credentialId: string) => Promise<void>;\n}\n\n/**\n * Creates an Authon store with reactive Svelte stores.\n *\n * Usage:\n * ```ts\n * import { createAuthonStore } from '@authon/svelte'\n *\n * const authon = createAuthonStore('pk_live_...')\n *\n * // In your component:\n * $: user = $authon.user\n * $: isSignedIn = $authon.isSignedIn\n * ```\n */\nexport function createAuthonStore(\n publishableKey: string,\n config?: Omit<AuthonConfig, 'mode'>,\n): AuthonStore {\n const client = new Authon(publishableKey, config);\n const userStore = writable<AuthonUser | null>(null);\n const isLoadingStore = writable(true);\n\n const isSignedIn = derived(userStore, ($user) => $user !== null);\n\n client.on('signedIn', (user) => {\n userStore.set(user as AuthonUser);\n isLoadingStore.set(false);\n });\n\n client.on('signedOut', () => {\n userStore.set(null);\n });\n\n client.on('error', () => {\n isLoadingStore.set(false);\n });\n\n const existingUser = client.getUser();\n if (existingUser) {\n userStore.set(existingUser);\n }\n isLoadingStore.set(false);\n\n return {\n user: { subscribe: userStore.subscribe },\n isSignedIn,\n isLoading: { subscribe: isLoadingStore.subscribe },\n signOut: async () => {\n await client.signOut();\n userStore.set(null);\n },\n openSignIn: () => client.openSignIn(),\n openSignUp: () => client.openSignUp(),\n getToken: () => client.getToken(),\n destroy: () => client.destroy(),\n client,\n // Web3\n web3GetNonce: (address, chain, walletType, chainId?) =>\n client.web3GetNonce(address, chain, walletType, chainId),\n web3Verify: (message, signature, address, chain, walletType) =>\n client.web3Verify(message, signature, address, chain, walletType),\n web3LinkWallet: (params) => client.linkWallet(params),\n web3UnlinkWallet: (walletId) => client.unlinkWallet(walletId),\n web3GetWallets: () => client.listWallets(),\n // Passwordless\n passwordlessSendCode: (email, type = 'otp') =>\n type === 'magic-link' ? client.sendMagicLink(email) : client.sendEmailOtp(email),\n passwordlessVerifyCode: (email, code) => client.verifyPasswordless({ email, code }),\n // Passkeys\n passkeyRegister: (name?) => client.registerPasskey(name),\n passkeyAuthenticate: (email?) => client.authenticateWithPasskey(email),\n passkeyList: () => client.listPasskeys(),\n passkeyDelete: (credentialId) => client.revokePasskey(credentialId),\n };\n}\n","import { setContext, getContext } from 'svelte';\nimport type { AuthonConfig } from '@authon/js';\nimport { createAuthonStore, type AuthonStore } from './store';\n\nconst AUTHON_CONTEXT_KEY = Symbol('authon');\n\n/**\n * Initialize Authon in a Svelte component tree.\n * Call this in your root layout or top-level component.\n *\n * Usage in +layout.svelte:\n * ```svelte\n * <script>\n * import { initAuthon } from '@authon/svelte'\n * const authon = initAuthon('pk_live_...')\n * </script>\n * ```\n */\nexport function initAuthon(\n publishableKey: string,\n config?: Omit<AuthonConfig, 'mode'>,\n): AuthonStore {\n const store = createAuthonStore(publishableKey, config);\n setContext(AUTHON_CONTEXT_KEY, store);\n return store;\n}\n\n/**\n * Get the Authon store from Svelte context.\n * Must be called within a component tree where `initAuthon` was called.\n *\n * Usage:\n * ```svelte\n * <script>\n * import { getAuthon } from '@authon/svelte'\n * const { user, isSignedIn, signOut } = getAuthon()\n * </script>\n * ```\n */\nexport function getAuthon(): AuthonStore {\n const store = getContext<AuthonStore | undefined>(AUTHON_CONTEXT_KEY);\n if (!store) {\n throw new Error('getAuthon() must be called within a component tree where initAuthon() was called.');\n }\n return store;\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\nimport { getProviderButtonConfig, type Authon } from '@authon/js';\n\nexport interface SocialButtonsOptions {\n /** Authon client instance */\n client: Authon;\n /** Target container element */\n container: HTMLElement;\n /** Called after successful OAuth sign-in */\n onSuccess?: () => void;\n /** Called on OAuth error */\n onError?: (error: Error) => void;\n /** Compact mode — icon-only square buttons in a row (default: false) */\n compact?: boolean;\n /** Gap between buttons in px (default: 10, compact default: 12) */\n gap?: number;\n /** Custom labels per provider */\n labels?: Partial<Record<OAuthProviderType, string>>;\n /** Icon size (default: 20, compact default: 24) */\n iconSize?: number;\n /** Border radius in px (default: 10) */\n borderRadius?: number;\n /** Button height in px (default: 48) */\n height?: number;\n /** Button size for compact mode in px (default: 48) */\n size?: number;\n}\n\n/**\n * Render social login buttons into a container element.\n *\n * Usage in +page.svelte:\n * ```svelte\n * <script>\n * import { getAuthon } from '@authon/svelte'\n * import { renderSocialButtons } from '@authon/svelte'\n * import { onMount } from 'svelte'\n *\n * const { client } = getAuthon()\n * let container: HTMLElement\n *\n * onMount(() => {\n * const cleanup = renderSocialButtons({\n * client,\n * container,\n * compact: true,\n * onError: (err) => console.error(err),\n * })\n * return cleanup\n * })\n * </script>\n *\n * <div bind:this={container}></div>\n * ```\n */\nexport function renderSocialButtons(options: SocialButtonsOptions): () => void {\n const {\n client,\n container,\n onSuccess,\n onError,\n compact = false,\n gap,\n labels,\n iconSize,\n borderRadius = 10,\n height = 48,\n size = 48,\n } = options;\n\n const resolvedGap = gap ?? (compact ? 12 : 10);\n const resolvedIconSize = iconSize ?? (compact ? 24 : 20);\n let loadingProvider: string | null = null;\n let buttons: HTMLButtonElement[] = [];\n\n const handleClick = async (provider: OAuthProviderType, btn: HTMLButtonElement) => {\n if (loadingProvider) return;\n loadingProvider = provider;\n btn.innerHTML = '<span style=\"display:inline-block;width:16px;height:16px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:authon-spin 0.6s linear infinite\"></span>';\n buttons.forEach((b) => (b.disabled = true));\n\n try {\n await client.signInWithOAuth(provider);\n onSuccess?.();\n } catch (e: any) {\n const error = e instanceof Error ? e : new Error(String(e));\n onError?.(error);\n } finally {\n loadingProvider = null;\n renderButtons(providers);\n }\n };\n\n let providers: OAuthProviderType[] = [];\n\n function renderButtons(providerList: OAuthProviderType[]) {\n container.innerHTML = '';\n buttons = [];\n\n // Inject keyframe if not present\n if (!document.getElementById('authon-spin-style')) {\n const style = document.createElement('style');\n style.id = 'authon-spin-style';\n style.textContent = '@keyframes authon-spin{to{transform:rotate(360deg)}}';\n document.head.appendChild(style);\n }\n\n const wrapper = document.createElement('div');\n wrapper.style.display = 'flex';\n wrapper.style.gap = `${resolvedGap}px`;\n\n if (compact) {\n wrapper.style.flexDirection = 'row';\n wrapper.style.flexWrap = 'wrap';\n wrapper.style.justifyContent = 'center';\n } else {\n wrapper.style.flexDirection = 'column';\n }\n\n for (const provider of providerList) {\n const colors = PROVIDER_COLORS[provider] || { bg: '#333', text: '#fff' };\n const displayName = PROVIDER_DISPLAY_NAMES[provider] || provider;\n const config = getProviderButtonConfig(provider);\n const iconSvg = config.iconSvg\n .replace(/width=\"\\d+\"/, `width=\"${resolvedIconSize}\"`)\n .replace(/height=\"\\d+\"/, `height=\"${resolvedIconSize}\"`);\n const needsBorder = colors.bg.toLowerCase() === '#ffffff';\n\n const btn = document.createElement('button');\n btn.setAttribute('aria-label', `Sign in with ${displayName}`);\n btn.style.display = 'flex';\n btn.style.alignItems = 'center';\n btn.style.justifyContent = 'center';\n btn.style.border = needsBorder ? '1px solid #dadce0' : 'none';\n btn.style.cursor = 'pointer';\n btn.style.backgroundColor = colors.bg;\n btn.style.color = colors.text;\n btn.style.borderRadius = `${borderRadius}px`;\n btn.style.transition = 'opacity 0.15s';\n btn.style.fontFamily = 'inherit';\n\n if (compact) {\n btn.style.width = `${size}px`;\n btn.style.height = `${size}px`;\n btn.style.padding = '0';\n btn.innerHTML = `<span style=\"display:flex;align-items:center\">${iconSvg}</span>`;\n } else {\n btn.style.width = '100%';\n btn.style.height = `${height}px`;\n btn.style.gap = '10px';\n btn.style.paddingLeft = '16px';\n btn.style.paddingRight = '16px';\n const buttonLabel = labels?.[provider] ?? `Continue with ${displayName}`;\n btn.innerHTML = `<span style=\"display:flex;align-items:center;flex-shrink:0\">${iconSvg}</span><span style=\"font-size:15px;font-weight:600;white-space:nowrap\">${buttonLabel}</span>`;\n }\n\n btn.addEventListener('click', () => handleClick(provider, btn));\n btn.addEventListener('mouseenter', () => (btn.style.opacity = '0.85'));\n btn.addEventListener('mouseleave', () => (btn.style.opacity = '1'));\n\n buttons.push(btn);\n wrapper.appendChild(btn);\n }\n\n container.appendChild(wrapper);\n }\n\n // Init\n client.getProviders().then((p: OAuthProviderType[]) => {\n providers = p;\n if (providers.length > 0) {\n renderButtons(providers);\n }\n });\n\n // Cleanup\n return () => {\n container.innerHTML = '';\n buttons = [];\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAiD;AACjD,gBAAuB;AAmDhB,SAAS,kBACd,gBACA,QACa;AACb,QAAM,SAAS,IAAI,iBAAO,gBAAgB,MAAM;AAChD,QAAM,gBAAY,uBAA4B,IAAI;AAClD,QAAM,qBAAiB,uBAAS,IAAI;AAEpC,QAAM,iBAAa,sBAAQ,WAAW,CAAC,UAAU,UAAU,IAAI;AAE/D,SAAO,GAAG,YAAY,CAAC,SAAS;AAC9B,cAAU,IAAI,IAAkB;AAChC,mBAAe,IAAI,KAAK;AAAA,EAC1B,CAAC;AAED,SAAO,GAAG,aAAa,MAAM;AAC3B,cAAU,IAAI,IAAI;AAAA,EACpB,CAAC;AAED,SAAO,GAAG,SAAS,MAAM;AACvB,mBAAe,IAAI,KAAK;AAAA,EAC1B,CAAC;AAED,QAAM,eAAe,OAAO,QAAQ;AACpC,MAAI,cAAc;AAChB,cAAU,IAAI,YAAY;AAAA,EAC5B;AACA,iBAAe,IAAI,KAAK;AAExB,SAAO;AAAA,IACL,MAAM,EAAE,WAAW,UAAU,UAAU;AAAA,IACvC;AAAA,IACA,WAAW,EAAE,WAAW,eAAe,UAAU;AAAA,IACjD,SAAS,YAAY;AACnB,YAAM,OAAO,QAAQ;AACrB,gBAAU,IAAI,IAAI;AAAA,IACpB;AAAA,IACA,YAAY,MAAM,OAAO,WAAW;AAAA,IACpC,YAAY,MAAM,OAAO,WAAW;AAAA,IACpC,UAAU,MAAM,OAAO,SAAS;AAAA,IAChC,SAAS,MAAM,OAAO,QAAQ;AAAA,IAC9B;AAAA;AAAA,IAEA,cAAc,CAAC,SAAS,OAAO,YAAY,YACzC,OAAO,aAAa,SAAS,OAAO,YAAY,OAAO;AAAA,IACzD,YAAY,CAAC,SAAS,WAAW,SAAS,OAAO,eAC/C,OAAO,WAAW,SAAS,WAAW,SAAS,OAAO,UAAU;AAAA,IAClE,gBAAgB,CAAC,WAAW,OAAO,WAAW,MAAM;AAAA,IACpD,kBAAkB,CAAC,aAAa,OAAO,aAAa,QAAQ;AAAA,IAC5D,gBAAgB,MAAM,OAAO,YAAY;AAAA;AAAA,IAEzC,sBAAsB,CAAC,OAAO,OAAO,UACnC,SAAS,eAAe,OAAO,cAAc,KAAK,IAAI,OAAO,aAAa,KAAK;AAAA,IACjF,wBAAwB,CAAC,OAAO,SAAS,OAAO,mBAAmB,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA,IAElF,iBAAiB,CAAC,SAAU,OAAO,gBAAgB,IAAI;AAAA,IACvD,qBAAqB,CAAC,UAAW,OAAO,wBAAwB,KAAK;AAAA,IACrE,aAAa,MAAM,OAAO,aAAa;AAAA,IACvC,eAAe,CAAC,iBAAiB,OAAO,cAAc,YAAY;AAAA,EACpE;AACF;;;AChHA,oBAAuC;AAIvC,IAAM,qBAAqB,uBAAO,QAAQ;AAcnC,SAAS,WACd,gBACA,QACa;AACb,QAAM,QAAQ,kBAAkB,gBAAgB,MAAM;AACtD,gCAAW,oBAAoB,KAAK;AACpC,SAAO;AACT;AAcO,SAAS,YAAyB;AACvC,QAAM,YAAQ,0BAAoC,kBAAkB;AACpE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,mFAAmF;AAAA,EACrG;AACA,SAAO;AACT;;;AC7CA,oBAAgF;AAChF,IAAAA,aAAqD;AAsD9C,SAAS,oBAAoB,SAA2C;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,EACT,IAAI;AAEJ,QAAM,cAAc,QAAQ,UAAU,KAAK;AAC3C,QAAM,mBAAmB,aAAa,UAAU,KAAK;AACrD,MAAI,kBAAiC;AACrC,MAAI,UAA+B,CAAC;AAEpC,QAAM,cAAc,OAAO,UAA6B,QAA2B;AACjF,QAAI,gBAAiB;AACrB,sBAAkB;AAClB,QAAI,YAAY;AAChB,YAAQ,QAAQ,CAAC,MAAO,EAAE,WAAW,IAAK;AAE1C,QAAI;AACF,YAAM,OAAO,gBAAgB,QAAQ;AACrC,kBAAY;AAAA,IACd,SAAS,GAAQ;AACf,YAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,gBAAU,KAAK;AAAA,IACjB,UAAE;AACA,wBAAkB;AAClB,oBAAc,SAAS;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,YAAiC,CAAC;AAEtC,WAAS,cAAc,cAAmC;AACxD,cAAU,YAAY;AACtB,cAAU,CAAC;AAGX,QAAI,CAAC,SAAS,eAAe,mBAAmB,GAAG;AACjD,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,KAAK;AACX,YAAM,cAAc;AACpB,eAAS,KAAK,YAAY,KAAK;AAAA,IACjC;AAEA,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,MAAM,UAAU;AACxB,YAAQ,MAAM,MAAM,GAAG,WAAW;AAElC,QAAI,SAAS;AACX,cAAQ,MAAM,gBAAgB;AAC9B,cAAQ,MAAM,WAAW;AACzB,cAAQ,MAAM,iBAAiB;AAAA,IACjC,OAAO;AACL,cAAQ,MAAM,gBAAgB;AAAA,IAChC;AAEA,eAAW,YAAY,cAAc;AACnC,YAAM,SAAS,8BAAgB,QAAQ,KAAK,EAAE,IAAI,QAAQ,MAAM,OAAO;AACvE,YAAM,cAAc,qCAAuB,QAAQ,KAAK;AACxD,YAAM,aAAS,oCAAwB,QAAQ;AAC/C,YAAM,UAAU,OAAO,QACpB,QAAQ,eAAe,UAAU,gBAAgB,GAAG,EACpD,QAAQ,gBAAgB,WAAW,gBAAgB,GAAG;AACzD,YAAM,cAAc,OAAO,GAAG,YAAY,MAAM;AAEhD,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,aAAa,cAAc,gBAAgB,WAAW,EAAE;AAC5D,UAAI,MAAM,UAAU;AACpB,UAAI,MAAM,aAAa;AACvB,UAAI,MAAM,iBAAiB;AAC3B,UAAI,MAAM,SAAS,cAAc,sBAAsB;AACvD,UAAI,MAAM,SAAS;AACnB,UAAI,MAAM,kBAAkB,OAAO;AACnC,UAAI,MAAM,QAAQ,OAAO;AACzB,UAAI,MAAM,eAAe,GAAG,YAAY;AACxC,UAAI,MAAM,aAAa;AACvB,UAAI,MAAM,aAAa;AAEvB,UAAI,SAAS;AACX,YAAI,MAAM,QAAQ,GAAG,IAAI;AACzB,YAAI,MAAM,SAAS,GAAG,IAAI;AAC1B,YAAI,MAAM,UAAU;AACpB,YAAI,YAAY,iDAAiD,OAAO;AAAA,MAC1E,OAAO;AACL,YAAI,MAAM,QAAQ;AAClB,YAAI,MAAM,SAAS,GAAG,MAAM;AAC5B,YAAI,MAAM,MAAM;AAChB,YAAI,MAAM,cAAc;AACxB,YAAI,MAAM,eAAe;AACzB,cAAM,cAAc,SAAS,QAAQ,KAAK,iBAAiB,WAAW;AACtE,YAAI,YAAY,+DAA+D,OAAO,0EAA0E,WAAW;AAAA,MAC7K;AAEA,UAAI,iBAAiB,SAAS,MAAM,YAAY,UAAU,GAAG,CAAC;AAC9D,UAAI,iBAAiB,cAAc,MAAO,IAAI,MAAM,UAAU,MAAO;AACrE,UAAI,iBAAiB,cAAc,MAAO,IAAI,MAAM,UAAU,GAAI;AAElE,cAAQ,KAAK,GAAG;AAChB,cAAQ,YAAY,GAAG;AAAA,IACzB;AAEA,cAAU,YAAY,OAAO;AAAA,EAC/B;AAGA,SAAO,aAAa,EAAE,KAAK,CAAC,MAA2B;AACrD,gBAAY;AACZ,QAAI,UAAU,SAAS,GAAG;AACxB,oBAAc,SAAS;AAAA,IACzB;AAAA,EACF,CAAC;AAGD,SAAO,MAAM;AACX,cAAU,YAAY;AACtB,cAAU,CAAC;AAAA,EACb;AACF;","names":["import_js"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/store.ts","../src/context.ts","../src/SocialButtons.ts"],"sourcesContent":["export { createAuthonStore } from './store';\nexport type { AuthonStore } from './store';\nexport { initAuthon, getAuthon } from './context';\nexport { renderSocialButtons } from './SocialButtons';\nexport type { SocialButtonsOptions } from './SocialButtons';\nexport type {\n PasskeyCredential,\n Web3Chain,\n Web3NonceResponse,\n Web3Wallet,\n Web3WalletType,\n} from '@authon/shared';\n\n// Svelte components are exported as raw .svelte source for the consumer's compiler.\n// Import them directly:\n// import SignIn from '@authon/svelte/SignIn.svelte'\n// import SignUp from '@authon/svelte/SignUp.svelte'\n","import { writable, derived, type Readable } from 'svelte/store';\nimport { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type {\n AuthonUser,\n PasskeyCredential,\n Web3Chain,\n Web3NonceResponse,\n Web3Wallet,\n Web3WalletType,\n} from '@authon/shared';\n\nexport interface AuthonStore {\n user: Readable<AuthonUser | null>;\n isSignedIn: Readable<boolean>;\n isLoading: Readable<boolean>;\n signOut: () => Promise<void>;\n openSignIn: () => Promise<void>;\n openSignUp: () => Promise<void>;\n getToken: () => string | null;\n destroy: () => void;\n client: Authon;\n // Web3\n web3GetNonce: (address: string, chain: Web3Chain, walletType: Web3WalletType, chainId?: number) => Promise<Web3NonceResponse>;\n web3Verify: (message: string, signature: string, address: string, chain: Web3Chain, walletType: Web3WalletType) => Promise<AuthonUser>;\n web3LinkWallet: (params: { address: string; chain: Web3Chain; walletType: Web3WalletType; chainId?: number; message: string; signature: string }) => Promise<Web3Wallet>;\n web3UnlinkWallet: (walletId: string) => Promise<void>;\n web3GetWallets: () => Promise<Web3Wallet[]>;\n // Passwordless\n passwordlessSendCode: (email: string, type?: 'magic-link' | 'otp') => Promise<void>;\n passwordlessVerifyCode: (email: string, code: string) => Promise<AuthonUser>;\n // Passkeys\n passkeyRegister: (name?: string) => Promise<PasskeyCredential>;\n passkeyAuthenticate: (email?: string) => Promise<AuthonUser>;\n passkeyList: () => Promise<PasskeyCredential[]>;\n passkeyDelete: (credentialId: string) => Promise<void>;\n}\n\n/**\n * Creates an Authon store with reactive Svelte stores.\n *\n * Usage:\n * ```ts\n * import { createAuthonStore } from '@authon/svelte'\n *\n * const authon = createAuthonStore('pk_live_...')\n *\n * // In your component:\n * $: user = $authon.user\n * $: isSignedIn = $authon.isSignedIn\n * ```\n */\nexport function createAuthonStore(\n publishableKey: string,\n config?: Omit<AuthonConfig, 'mode'>,\n): AuthonStore {\n const client = new Authon(publishableKey, config);\n const userStore = writable<AuthonUser | null>(null);\n const isLoadingStore = writable(true);\n\n const isSignedIn = derived(userStore, ($user) => $user !== null);\n\n client.on('signedIn', (user) => {\n userStore.set(user as AuthonUser);\n isLoadingStore.set(false);\n });\n\n client.on('signedOut', () => {\n userStore.set(null);\n });\n\n client.on('error', () => {\n isLoadingStore.set(false);\n });\n\n const existingUser = client.getUser();\n if (existingUser) {\n userStore.set(existingUser);\n }\n isLoadingStore.set(false);\n\n return {\n user: { subscribe: userStore.subscribe },\n isSignedIn,\n isLoading: { subscribe: isLoadingStore.subscribe },\n signOut: async () => {\n await client.signOut();\n userStore.set(null);\n },\n openSignIn: () => client.openSignIn(),\n openSignUp: () => client.openSignUp(),\n getToken: () => client.getToken(),\n destroy: () => client.destroy(),\n client,\n // Web3\n web3GetNonce: (address, chain, walletType, chainId?) =>\n client.web3GetNonce(address, chain, walletType, chainId),\n web3Verify: (message, signature, address, chain, walletType) =>\n client.web3Verify(message, signature, address, chain, walletType),\n web3LinkWallet: (params) => client.linkWallet(params),\n web3UnlinkWallet: (walletId) => client.unlinkWallet(walletId),\n web3GetWallets: () => client.listWallets(),\n // Passwordless\n passwordlessSendCode: (email, type = 'otp') =>\n type === 'magic-link' ? client.sendMagicLink(email) : client.sendEmailOtp(email),\n passwordlessVerifyCode: (email, code) => client.verifyPasswordless({ email, code }),\n // Passkeys\n passkeyRegister: (name?) => client.registerPasskey(name),\n passkeyAuthenticate: (email?) => client.authenticateWithPasskey(email),\n passkeyList: () => client.listPasskeys(),\n passkeyDelete: (credentialId) => client.revokePasskey(credentialId),\n };\n}\n","import { setContext, getContext } from 'svelte';\nimport type { AuthonConfig } from '@authon/js';\nimport { createAuthonStore, type AuthonStore } from './store';\n\nconst AUTHON_CONTEXT_KEY = Symbol('authon');\n\n/**\n * Initialize Authon in a Svelte component tree.\n * Call this in your root layout or top-level component.\n *\n * Usage in +layout.svelte:\n * ```svelte\n * <script>\n * import { initAuthon } from '@authon/svelte'\n * const authon = initAuthon('pk_live_...')\n * </script>\n * ```\n */\nexport function initAuthon(\n publishableKey: string,\n config?: Omit<AuthonConfig, 'mode'>,\n): AuthonStore {\n const store = createAuthonStore(publishableKey, config);\n setContext(AUTHON_CONTEXT_KEY, store);\n return store;\n}\n\n/**\n * Get the Authon store from Svelte context.\n * Must be called within a component tree where `initAuthon` was called.\n *\n * Usage:\n * ```svelte\n * <script>\n * import { getAuthon } from '@authon/svelte'\n * const { user, isSignedIn, signOut } = getAuthon()\n * </script>\n * ```\n */\nexport function getAuthon(): AuthonStore {\n const store = getContext<AuthonStore | undefined>(AUTHON_CONTEXT_KEY);\n if (!store) {\n throw new Error('getAuthon() must be called within a component tree where initAuthon() was called.');\n }\n return store;\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\nimport { getProviderButtonConfig, type Authon } from '@authon/js';\n\nexport interface SocialButtonsOptions {\n /** Authon client instance */\n client: Authon;\n /** Target container element */\n container: HTMLElement;\n /** Called after successful OAuth sign-in */\n onSuccess?: () => void;\n /** Called on OAuth error */\n onError?: (error: Error) => void;\n /** Compact mode — icon-only square buttons in a row (default: false) */\n compact?: boolean;\n /** Gap between buttons in px (default: 10, compact default: 12) */\n gap?: number;\n /** Custom labels per provider */\n labels?: Partial<Record<OAuthProviderType, string>>;\n /** Icon size (default: 20, compact default: 24) */\n iconSize?: number;\n /** Border radius in px (default: 10) */\n borderRadius?: number;\n /** Button height in px (default: 48) */\n height?: number;\n /** Button size for compact mode in px (default: 48) */\n size?: number;\n}\n\n/**\n * Render social login buttons into a container element.\n *\n * Usage in +page.svelte:\n * ```svelte\n * <script>\n * import { getAuthon } from '@authon/svelte'\n * import { renderSocialButtons } from '@authon/svelte'\n * import { onMount } from 'svelte'\n *\n * const { client } = getAuthon()\n * let container: HTMLElement\n *\n * onMount(() => {\n * const cleanup = renderSocialButtons({\n * client,\n * container,\n * compact: true,\n * onError: (err) => console.error(err),\n * })\n * return cleanup\n * })\n * </script>\n *\n * <div bind:this={container}></div>\n * ```\n */\nexport function renderSocialButtons(options: SocialButtonsOptions): () => void {\n const {\n client,\n container,\n onSuccess,\n onError,\n compact = false,\n gap,\n labels,\n iconSize,\n borderRadius = 10,\n height = 48,\n size = 48,\n } = options;\n\n const resolvedGap = gap ?? (compact ? 12 : 10);\n const resolvedIconSize = iconSize ?? (compact ? 24 : 20);\n let loadingProvider: string | null = null;\n let buttons: HTMLButtonElement[] = [];\n\n const handleClick = async (provider: OAuthProviderType, btn: HTMLButtonElement) => {\n if (loadingProvider) return;\n loadingProvider = provider;\n btn.innerHTML = '<span style=\"display:inline-block;width:16px;height:16px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:authon-spin 0.6s linear infinite\"></span>';\n buttons.forEach((b) => (b.disabled = true));\n\n try {\n await client.signInWithOAuth(provider);\n onSuccess?.();\n } catch (e: any) {\n const error = e instanceof Error ? e : new Error(String(e));\n onError?.(error);\n } finally {\n loadingProvider = null;\n renderButtons(providers);\n }\n };\n\n let providers: OAuthProviderType[] = [];\n\n function renderButtons(providerList: OAuthProviderType[]) {\n container.innerHTML = '';\n buttons = [];\n\n // Inject keyframe if not present\n if (!document.getElementById('authon-spin-style')) {\n const style = document.createElement('style');\n style.id = 'authon-spin-style';\n style.textContent = '@keyframes authon-spin{to{transform:rotate(360deg)}}';\n document.head.appendChild(style);\n }\n\n const wrapper = document.createElement('div');\n wrapper.style.display = 'flex';\n wrapper.style.gap = `${resolvedGap}px`;\n\n if (compact) {\n wrapper.style.flexDirection = 'row';\n wrapper.style.flexWrap = 'wrap';\n wrapper.style.justifyContent = 'center';\n } else {\n wrapper.style.flexDirection = 'column';\n }\n\n for (const provider of providerList) {\n const colors = PROVIDER_COLORS[provider] || { bg: '#333', text: '#fff' };\n const displayName = PROVIDER_DISPLAY_NAMES[provider] || provider;\n const config = getProviderButtonConfig(provider);\n const iconSvg = config.iconSvg\n .replace(/width=\"\\d+\"/, `width=\"${resolvedIconSize}\"`)\n .replace(/height=\"\\d+\"/, `height=\"${resolvedIconSize}\"`);\n const needsBorder = colors.bg.toLowerCase() === '#ffffff';\n\n const btn = document.createElement('button');\n btn.setAttribute('aria-label', `Sign in with ${displayName}`);\n btn.style.display = 'flex';\n btn.style.alignItems = 'center';\n btn.style.justifyContent = 'center';\n btn.style.border = needsBorder ? '1px solid #dadce0' : 'none';\n btn.style.cursor = 'pointer';\n btn.style.backgroundColor = colors.bg;\n btn.style.color = colors.text;\n btn.style.borderRadius = `${borderRadius}px`;\n btn.style.transition = 'opacity 0.15s';\n btn.style.fontFamily = 'inherit';\n\n if (compact) {\n btn.style.width = `${size}px`;\n btn.style.height = `${size}px`;\n btn.style.padding = '0';\n btn.innerHTML = `<span style=\"display:flex;align-items:center\">${iconSvg}</span>`;\n } else {\n btn.style.width = '100%';\n btn.style.height = `${height}px`;\n btn.style.gap = '10px';\n btn.style.paddingLeft = '16px';\n btn.style.paddingRight = '16px';\n const buttonLabel = labels?.[provider] ?? `Continue with ${displayName}`;\n btn.innerHTML = `<span style=\"display:flex;align-items:center;flex-shrink:0\">${iconSvg}</span><span style=\"font-size:15px;font-weight:600;white-space:nowrap\">${buttonLabel}</span>`;\n }\n\n btn.addEventListener('click', () => handleClick(provider, btn));\n btn.addEventListener('mouseenter', () => (btn.style.opacity = '0.85'));\n btn.addEventListener('mouseleave', () => (btn.style.opacity = '1'));\n\n buttons.push(btn);\n wrapper.appendChild(btn);\n }\n\n container.appendChild(wrapper);\n }\n\n // Init\n client.getProviders().then((p: OAuthProviderType[]) => {\n providers = p;\n if (providers.length > 0) {\n renderButtons(providers);\n }\n });\n\n // Cleanup\n return () => {\n container.innerHTML = '';\n buttons = [];\n };\n}\n"],"mappings":"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","names":["import_js"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authon/svelte",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Authon Svelte SDK — stores and components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -11,10 +11,13 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"import": "./dist/index.js",
|
|
13
13
|
"require": "./dist/index.cjs"
|
|
14
|
-
}
|
|
14
|
+
},
|
|
15
|
+
"./SignIn.svelte": "./src/components/SignIn.svelte",
|
|
16
|
+
"./SignUp.svelte": "./src/components/SignUp.svelte"
|
|
15
17
|
},
|
|
16
18
|
"files": [
|
|
17
|
-
"dist"
|
|
19
|
+
"dist",
|
|
20
|
+
"src/components"
|
|
18
21
|
],
|
|
19
22
|
"scripts": {
|
|
20
23
|
"build": "tsup",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, onDestroy, createEventDispatcher } from 'svelte';
|
|
3
|
+
import { Authon } from '@authon/js';
|
|
4
|
+
import type { AuthonUser } from '@authon/shared';
|
|
5
|
+
|
|
6
|
+
export let publishableKey: string;
|
|
7
|
+
export let apiUrl: string = 'https://api.authon.dev';
|
|
8
|
+
export let theme: 'light' | 'dark' | 'auto' = 'auto';
|
|
9
|
+
export let locale: string | undefined = undefined;
|
|
10
|
+
|
|
11
|
+
const dispatch = createEventDispatcher<{ signIn: { user: AuthonUser } }>();
|
|
12
|
+
|
|
13
|
+
let container: HTMLDivElement;
|
|
14
|
+
let authonInstance: Authon | null = null;
|
|
15
|
+
let unsubscribe: (() => void) | null = null;
|
|
16
|
+
const containerId = `authon-signin-${Math.random().toString(36).slice(2, 8)}`;
|
|
17
|
+
|
|
18
|
+
onMount(() => {
|
|
19
|
+
container.id = containerId;
|
|
20
|
+
authonInstance = new Authon(publishableKey, {
|
|
21
|
+
mode: 'embedded',
|
|
22
|
+
containerId,
|
|
23
|
+
apiUrl,
|
|
24
|
+
theme,
|
|
25
|
+
locale,
|
|
26
|
+
});
|
|
27
|
+
unsubscribe = authonInstance.on('signedIn', (user) => {
|
|
28
|
+
dispatch('signIn', { user: user as AuthonUser });
|
|
29
|
+
});
|
|
30
|
+
authonInstance.openSignIn();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
onDestroy(() => {
|
|
34
|
+
unsubscribe?.();
|
|
35
|
+
authonInstance?.destroy();
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div bind:this={container}></div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, onDestroy, createEventDispatcher } from 'svelte';
|
|
3
|
+
import { Authon } from '@authon/js';
|
|
4
|
+
import type { AuthonUser } from '@authon/shared';
|
|
5
|
+
|
|
6
|
+
export let publishableKey: string;
|
|
7
|
+
export let apiUrl: string = 'https://api.authon.dev';
|
|
8
|
+
export let theme: 'light' | 'dark' | 'auto' = 'auto';
|
|
9
|
+
export let locale: string | undefined = undefined;
|
|
10
|
+
|
|
11
|
+
const dispatch = createEventDispatcher<{ signUp: { user: AuthonUser } }>();
|
|
12
|
+
|
|
13
|
+
let container: HTMLDivElement;
|
|
14
|
+
let authonInstance: Authon | null = null;
|
|
15
|
+
let unsubscribe: (() => void) | null = null;
|
|
16
|
+
const containerId = `authon-signup-${Math.random().toString(36).slice(2, 8)}`;
|
|
17
|
+
|
|
18
|
+
onMount(() => {
|
|
19
|
+
container.id = containerId;
|
|
20
|
+
authonInstance = new Authon(publishableKey, {
|
|
21
|
+
mode: 'embedded',
|
|
22
|
+
containerId,
|
|
23
|
+
apiUrl,
|
|
24
|
+
theme,
|
|
25
|
+
locale,
|
|
26
|
+
});
|
|
27
|
+
unsubscribe = authonInstance.on('signedIn', (user) => {
|
|
28
|
+
dispatch('signUp', { user: user as AuthonUser });
|
|
29
|
+
});
|
|
30
|
+
authonInstance.openSignUp();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
onDestroy(() => {
|
|
34
|
+
unsubscribe?.();
|
|
35
|
+
authonInstance?.destroy();
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div bind:this={container}></div>
|