@authon/svelte 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md ADDED
@@ -0,0 +1,141 @@
1
+ [English](./README.md) | **한국어**
2
+
3
+ # @authon/svelte
4
+
5
+ [Authon](https://authon.dev)을 위한 Svelte SDK — store, 액션, 컴포넌트를 제공합니다.
6
+
7
+ ## 설치
8
+
9
+ ```bash
10
+ npm install @authon/svelte
11
+ # 또는
12
+ pnpm add @authon/svelte
13
+ ```
14
+
15
+ `svelte >= 4.0.0`이 필요합니다.
16
+
17
+ ## 빠른 시작
18
+
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
+ ```svelte
33
+ <script>
34
+ import { user, isSignedIn, isLoading } from '@authon/svelte';
35
+ import { openSignIn, signOut } from '@authon/svelte';
36
+ </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}
46
+ ```
47
+
48
+ ### 3. 컴포넌트 사용
49
+
50
+ ```svelte
51
+ <script>
52
+ import { SignedIn, SignedOut, UserButton } from '@authon/svelte';
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>
96
+ import { getAuthon } from '@authon/svelte';
97
+ import { AuthonMfaRequiredError } from '@authon/js';
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
+ }
125
+ </script>
126
+
127
+ {#if qrSvg}
128
+ {@html qrSvg}
129
+ <p>Scan with your authenticator app</p>
130
+ {/if}
131
+ ```
132
+
133
+ 전체 API 레퍼런스는 [`@authon/js` MFA 문서](../js/README.md#multi-factor-authentication-mfa)를 참고하세요.
134
+
135
+ ## 문서
136
+
137
+ [authon.dev/docs](https://authon.dev/docs)
138
+
139
+ ## 라이선스
140
+
141
+ [MIT](../../LICENSE)
package/README.md CHANGED
@@ -1,89 +1,459 @@
1
+ **English** | [한국어](./README.ko.md)
2
+
1
3
  # @authon/svelte
2
4
 
3
- Svelte SDK for [Authon](https://authon.dev) — stores, actions, and components.
5
+ Svelte integration for [Authon](https://authon.dev) — reactive stores, context-based setup, and social login buttons.
4
6
 
5
7
  ## Install
6
8
 
7
9
  ```bash
8
- npm install @authon/svelte
9
- # or
10
- pnpm add @authon/svelte
10
+ npm install @authon/svelte @authon/js
11
11
  ```
12
12
 
13
13
  Requires `svelte >= 4.0.0`.
14
14
 
15
- ## Quick Start
15
+ ## Setup
16
16
 
17
- ### 1. Initialize
17
+ Initialize Authon in your root layout component and provide it to the component tree via Svelte context:
18
18
 
19
- ```ts
20
- // src/lib/authon.ts
21
- import { initAuthon } from '@authon/svelte';
19
+ ```svelte
20
+ <!-- src/routes/+layout.svelte -->
21
+ <script lang="ts">
22
+ import { initAuthon } from '@authon/svelte'
23
+ import { onDestroy } from 'svelte'
22
24
 
23
- export const authon = initAuthon({
24
- publishableKey: 'pk_live_...',
25
- });
25
+ const authon = initAuthon('pk_live_...', {
26
+ theme: 'auto',
27
+ locale: 'en',
28
+ })
29
+
30
+ onDestroy(() => authon.destroy())
31
+ </script>
32
+
33
+ <slot />
26
34
  ```
27
35
 
28
- ### 2. Use Stores
36
+ Then access the store in any child component:
29
37
 
30
38
  ```svelte
31
- <script>
32
- import { user, isSignedIn, isLoading } from '@authon/svelte';
33
- import { openSignIn, signOut } from '@authon/svelte';
39
+ <!-- src/routes/+page.svelte -->
40
+ <script lang="ts">
41
+ import { getAuthon } from '@authon/svelte'
42
+
43
+ const { user, isSignedIn, isLoading, openSignIn, signOut } = getAuthon()
34
44
  </script>
35
45
 
36
46
  {#if $isLoading}
37
47
  <p>Loading...</p>
38
48
  {:else if $isSignedIn}
39
49
  <p>Welcome, {$user?.displayName}</p>
40
- <button on:click={signOut}>Sign Out</button>
50
+ <button on:click={signOut}>Sign out</button>
51
+ {:else}
52
+ <button on:click={openSignIn}>Sign in</button>
53
+ {/if}
54
+ ```
55
+
56
+ ## API Reference
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()`
72
+
73
+ Retrieves the `AuthonStore` from Svelte context. Must be called within a component that is a descendant of the component where `initAuthon` was called.
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
125
+
126
+ ```svelte
127
+ <script lang="ts">
128
+ import { getAuthon } from '@authon/svelte'
129
+
130
+ const { user, isSignedIn, isLoading, openSignIn, signOut } = getAuthon()
131
+ </script>
132
+
133
+ {#if $isLoading}
134
+ <p>Loading...</p>
135
+ {:else if $isSignedIn}
136
+ <p>Hello, {$user?.displayName ?? $user?.email}</p>
137
+ <button on:click={signOut}>Sign out</button>
41
138
  {:else}
42
- <button on:click={openSignIn}>Sign In</button>
139
+ <button on:click={openSignIn}>Sign in</button>
43
140
  {/if}
44
141
  ```
45
142
 
46
- ### 3. Use Components
143
+ ### Email + password sign-in
47
144
 
48
145
  ```svelte
49
- <script>
50
- import { SignedIn, SignedOut, UserButton } from '@authon/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
+ }
51
167
  </script>
52
168
 
53
- <SignedIn>
54
- <UserButton />
55
- </SignedIn>
56
- <SignedOut>
57
- <button on:click={openSignIn}>Sign In</button>
58
- </SignedOut>
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>
59
175
  ```
60
176
 
61
- ## API Reference
177
+ ### OAuth sign-in
178
+
179
+ ```svelte
180
+ <script lang="ts">
181
+ import { getAuthon, renderSocialButtons } from '@authon/svelte'
182
+ import { onMount, onDestroy } from 'svelte'
183
+
184
+ const { client } = getAuthon()
185
+ let container: HTMLElement
186
+ let cleanup: (() => void) | undefined
187
+
188
+ onMount(() => {
189
+ cleanup = renderSocialButtons({
190
+ client,
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
+ }
233
+ </script>
234
+
235
+ <button on:click={initMfaSetup}>Enable MFA</button>
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>
244
+ {/if}
245
+ ```
246
+
247
+ ### MFA verification on sign-in
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
276
+
277
+ ```svelte
278
+ <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
+ }
289
+ </script>
290
+
291
+ {#if sent}
292
+ <p>Check your inbox for a sign-in link.</p>
293
+ {:else}
294
+ <input bind:value={email} type="email" placeholder="Email" />
295
+ <button on:click={sendMagicLink}>Send magic link</button>
296
+ {/if}
297
+ ```
298
+
299
+ ### Passwordless — email OTP
300
+
301
+ ```svelte
302
+ <script lang="ts">
303
+ import { getAuthon } from '@authon/svelte'
304
+
305
+ const { client } = getAuthon()
306
+ let email = ''
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)
318
+ }
319
+ </script>
320
+
321
+ {#if step === 'email'}
322
+ <input bind:value={email} type="email" placeholder="Email" />
323
+ <button on:click={sendOtp}>Send code</button>
324
+ {:else}
325
+ <input bind:value={otp} placeholder="6-digit code" />
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>
388
+ ```
62
389
 
63
- ### Stores
390
+ ### Profile update
64
391
 
65
- | Store | Type | Description |
66
- |-------|------|-------------|
67
- | `user` | `Readable<AuthonUser \| null>` | Current user |
68
- | `isSignedIn` | `Readable<boolean>` | Whether the user is signed in |
69
- | `isLoading` | `Readable<boolean>` | Whether auth state is loading |
392
+ ```svelte
393
+ <script lang="ts">
394
+ import { getAuthon } from '@authon/svelte'
70
395
 
71
- ### Actions
396
+ const { client } = getAuthon()
72
397
 
73
- | Function | Returns | Description |
74
- |----------|---------|-------------|
75
- | `openSignIn()` | `Promise<void>` | Open sign-in modal |
76
- | `openSignUp()` | `Promise<void>` | Open sign-up modal |
77
- | `signOut()` | `Promise<void>` | Sign out |
78
- | `getToken()` | `string \| null` | Get current access token |
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
+ }
407
+ </script>
408
+ ```
79
409
 
80
- ### Components
410
+ ### Session management
81
411
 
82
- | Component | Description |
83
- |-----------|-------------|
84
- | `<SignedIn>` | Renders slot only when signed in |
85
- | `<SignedOut>` | Renders slot only when signed out |
86
- | `<UserButton>` | Avatar dropdown with sign-out |
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
+
421
+ onMount(async () => {
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>
439
+ ```
440
+
441
+ ## Store options
442
+
443
+ | Option | Type | Default | Description |
444
+ |---|---|---|---|
445
+ | `publishableKey` | `string` | required | Your Authon publishable key |
446
+ | `config.theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | UI theme |
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 |
450
+
451
+ ## TypeScript
452
+
453
+ ```ts
454
+ import type { AuthonStore, SocialButtonsOptions } from '@authon/svelte'
455
+ import type { AuthonUser, SessionInfo, PasskeyCredential, Web3Wallet } from '@authon/shared'
456
+ ```
87
457
 
88
458
  ## Documentation
89
459
 
package/dist/index.cjs CHANGED
@@ -62,7 +62,21 @@ function createAuthonStore(publishableKey, config) {
62
62
  openSignUp: () => client.openSignUp(),
63
63
  getToken: () => client.getToken(),
64
64
  destroy: () => client.destroy(),
65
- client
65
+ client,
66
+ // Web3
67
+ web3GetNonce: (address, chain, walletType, chainId) => client.web3GetNonce(address, chain, walletType, chainId),
68
+ web3Verify: (message, signature, address, chain, walletType) => client.web3Verify(message, signature, address, chain, walletType),
69
+ web3LinkWallet: (params) => client.linkWallet(params),
70
+ web3UnlinkWallet: (walletId) => client.unlinkWallet(walletId),
71
+ web3GetWallets: () => client.listWallets(),
72
+ // Passwordless
73
+ passwordlessSendCode: (email, type = "otp") => type === "magic-link" ? client.sendMagicLink(email) : client.sendEmailOtp(email),
74
+ passwordlessVerifyCode: (email, code) => client.verifyPasswordless({ email, code }),
75
+ // Passkeys
76
+ passkeyRegister: (name) => client.registerPasskey(name),
77
+ passkeyAuthenticate: (email) => client.authenticateWithPasskey(email),
78
+ passkeyList: () => client.listPasskeys(),
79
+ passkeyDelete: (credentialId) => client.revokePasskey(credentialId)
66
80
  };
67
81
  }
68
82
 
@@ -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';\n","import { writable, derived, type Readable } from 'svelte/store';\nimport { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type { AuthonUser } 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}\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 };\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"]}
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":"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","names":["import_js"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Readable } from 'svelte/store';
2
2
  import { Authon, AuthonConfig } from '@authon/js';
3
- import { AuthonUser, OAuthProviderType } from '@authon/shared';
3
+ import { AuthonUser, Web3Chain, Web3WalletType, Web3NonceResponse, Web3Wallet, PasskeyCredential, OAuthProviderType } from '@authon/shared';
4
+ export { PasskeyCredential, Web3Chain, Web3NonceResponse, Web3Wallet, Web3WalletType } from '@authon/shared';
4
5
 
5
6
  interface AuthonStore {
6
7
  user: Readable<AuthonUser | null>;
@@ -12,6 +13,24 @@ interface AuthonStore {
12
13
  getToken: () => string | null;
13
14
  destroy: () => void;
14
15
  client: Authon;
16
+ web3GetNonce: (address: string, chain: Web3Chain, walletType: Web3WalletType, chainId?: number) => Promise<Web3NonceResponse>;
17
+ web3Verify: (message: string, signature: string, address: string, chain: Web3Chain, walletType: Web3WalletType) => Promise<AuthonUser>;
18
+ web3LinkWallet: (params: {
19
+ address: string;
20
+ chain: Web3Chain;
21
+ walletType: Web3WalletType;
22
+ chainId?: number;
23
+ message: string;
24
+ signature: string;
25
+ }) => Promise<Web3Wallet>;
26
+ web3UnlinkWallet: (walletId: string) => Promise<void>;
27
+ web3GetWallets: () => Promise<Web3Wallet[]>;
28
+ passwordlessSendCode: (email: string, type?: 'magic-link' | 'otp') => Promise<void>;
29
+ passwordlessVerifyCode: (email: string, code: string) => Promise<AuthonUser>;
30
+ passkeyRegister: (name?: string) => Promise<PasskeyCredential>;
31
+ passkeyAuthenticate: (email?: string) => Promise<AuthonUser>;
32
+ passkeyList: () => Promise<PasskeyCredential[]>;
33
+ passkeyDelete: (credentialId: string) => Promise<void>;
15
34
  }
16
35
  /**
17
36
  * Creates an Authon store with reactive Svelte stores.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Readable } from 'svelte/store';
2
2
  import { Authon, AuthonConfig } from '@authon/js';
3
- import { AuthonUser, OAuthProviderType } from '@authon/shared';
3
+ import { AuthonUser, Web3Chain, Web3WalletType, Web3NonceResponse, Web3Wallet, PasskeyCredential, OAuthProviderType } from '@authon/shared';
4
+ export { PasskeyCredential, Web3Chain, Web3NonceResponse, Web3Wallet, Web3WalletType } from '@authon/shared';
4
5
 
5
6
  interface AuthonStore {
6
7
  user: Readable<AuthonUser | null>;
@@ -12,6 +13,24 @@ interface AuthonStore {
12
13
  getToken: () => string | null;
13
14
  destroy: () => void;
14
15
  client: Authon;
16
+ web3GetNonce: (address: string, chain: Web3Chain, walletType: Web3WalletType, chainId?: number) => Promise<Web3NonceResponse>;
17
+ web3Verify: (message: string, signature: string, address: string, chain: Web3Chain, walletType: Web3WalletType) => Promise<AuthonUser>;
18
+ web3LinkWallet: (params: {
19
+ address: string;
20
+ chain: Web3Chain;
21
+ walletType: Web3WalletType;
22
+ chainId?: number;
23
+ message: string;
24
+ signature: string;
25
+ }) => Promise<Web3Wallet>;
26
+ web3UnlinkWallet: (walletId: string) => Promise<void>;
27
+ web3GetWallets: () => Promise<Web3Wallet[]>;
28
+ passwordlessSendCode: (email: string, type?: 'magic-link' | 'otp') => Promise<void>;
29
+ passwordlessVerifyCode: (email: string, code: string) => Promise<AuthonUser>;
30
+ passkeyRegister: (name?: string) => Promise<PasskeyCredential>;
31
+ passkeyAuthenticate: (email?: string) => Promise<AuthonUser>;
32
+ passkeyList: () => Promise<PasskeyCredential[]>;
33
+ passkeyDelete: (credentialId: string) => Promise<void>;
15
34
  }
16
35
  /**
17
36
  * Creates an Authon store with reactive Svelte stores.
package/dist/index.js CHANGED
@@ -33,7 +33,21 @@ function createAuthonStore(publishableKey, config) {
33
33
  openSignUp: () => client.openSignUp(),
34
34
  getToken: () => client.getToken(),
35
35
  destroy: () => client.destroy(),
36
- client
36
+ client,
37
+ // Web3
38
+ web3GetNonce: (address, chain, walletType, chainId) => client.web3GetNonce(address, chain, walletType, chainId),
39
+ web3Verify: (message, signature, address, chain, walletType) => client.web3Verify(message, signature, address, chain, walletType),
40
+ web3LinkWallet: (params) => client.linkWallet(params),
41
+ web3UnlinkWallet: (walletId) => client.unlinkWallet(walletId),
42
+ web3GetWallets: () => client.listWallets(),
43
+ // Passwordless
44
+ passwordlessSendCode: (email, type = "otp") => type === "magic-link" ? client.sendMagicLink(email) : client.sendEmailOtp(email),
45
+ passwordlessVerifyCode: (email, code) => client.verifyPasswordless({ email, code }),
46
+ // Passkeys
47
+ passkeyRegister: (name) => client.registerPasskey(name),
48
+ passkeyAuthenticate: (email) => client.authenticateWithPasskey(email),
49
+ passkeyList: () => client.listPasskeys(),
50
+ passkeyDelete: (credentialId) => client.revokePasskey(credentialId)
37
51
  };
38
52
  }
39
53
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store.ts","../src/context.ts","../src/SocialButtons.ts"],"sourcesContent":["import { writable, derived, type Readable } from 'svelte/store';\nimport { Authon } from '@authon/js';\nimport type { AuthonConfig } from '@authon/js';\nimport type { AuthonUser } 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}\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 };\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":[]}
1
+ {"version":3,"sources":["../src/store.ts","../src/context.ts","../src/SocialButtons.ts"],"sourcesContent":["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,SAAS,UAAU,eAA8B;AACjD,SAAS,cAAc;AAmDhB,SAAS,kBACd,gBACA,QACa;AACb,QAAM,SAAS,IAAI,OAAO,gBAAgB,MAAM;AAChD,QAAM,YAAY,SAA4B,IAAI;AAClD,QAAM,iBAAiB,SAAS,IAAI;AAEpC,QAAM,aAAa,QAAQ,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,SAAS,YAAY,kBAAkB;AAIvC,IAAM,qBAAqB,uBAAO,QAAQ;AAcnC,SAAS,WACd,gBACA,QACa;AACb,QAAM,QAAQ,kBAAkB,gBAAgB,MAAM;AACtD,aAAW,oBAAoB,KAAK;AACpC,SAAO;AACT;AAcO,SAAS,YAAyB;AACvC,QAAM,QAAQ,WAAoC,kBAAkB;AACpE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,mFAAmF;AAAA,EACrG;AACA,SAAO;AACT;;;AC7CA,SAAS,iBAAiB,8BAAsD;AAChF,SAAS,+BAA4C;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,gBAAgB,QAAQ,KAAK,EAAE,IAAI,QAAQ,MAAM,OAAO;AACvE,YAAM,cAAc,uBAAuB,QAAQ,KAAK;AACxD,YAAM,SAAS,wBAAwB,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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authon/svelte",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Authon Svelte SDK — stores and components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -37,8 +37,8 @@
37
37
  "store"
38
38
  ],
39
39
  "dependencies": {
40
- "@authon/js": "^0.2.1",
41
- "@authon/shared": "^0.2.0"
40
+ "@authon/js": "workspace:^",
41
+ "@authon/shared": "workspace:^"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "svelte": "^4.0.0 || ^5.0.0"