@mrgnw/anahtar 0.0.11 → 0.0.12
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/dist/components/AuthFlow.svelte +25 -16
- package/dist/components/AuthFlow.svelte.d.ts +3 -0
- package/dist/components/PasskeyPrompt.svelte +10 -7
- package/dist/components/PasskeyPrompt.svelte.d.ts +2 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/i18n/ar.d.ts +3 -0
- package/dist/i18n/ar.js +28 -0
- package/dist/i18n/de.d.ts +3 -0
- package/dist/i18n/de.js +28 -0
- package/dist/i18n/en.d.ts +3 -0
- package/dist/i18n/en.js +28 -0
- package/dist/i18n/es.d.ts +3 -0
- package/dist/i18n/es.js +28 -0
- package/dist/i18n/fr.d.ts +3 -0
- package/dist/i18n/fr.js +28 -0
- package/dist/i18n/index.d.ts +7 -0
- package/dist/i18n/index.js +41 -0
- package/dist/i18n/ja.d.ts +3 -0
- package/dist/i18n/ja.js +28 -0
- package/dist/i18n/ko.d.ts +3 -0
- package/dist/i18n/ko.js +28 -0
- package/dist/i18n/pt.d.ts +3 -0
- package/dist/i18n/pt.js +28 -0
- package/dist/i18n/tr.d.ts +3 -0
- package/dist/i18n/tr.js +28 -0
- package/dist/i18n/types.d.ts +27 -0
- package/dist/i18n/types.js +1 -0
- package/dist/i18n/zh.d.ts +3 -0
- package/dist/i18n/zh.js +28 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/kit/handlers.js +35 -21
- package/dist/types.d.ts +5 -1
- package/package.json +90 -90
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { guessDeviceName } from '../device.js';
|
|
3
|
+
import { resolveMessages, detectLocaleClient, type AuthMessages } from '../i18n/index.js';
|
|
3
4
|
import OtpInput from './OtpInput.svelte';
|
|
4
5
|
import PasskeyPrompt from './PasskeyPrompt.svelte';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
apiBase?: string;
|
|
9
|
+
locale?: string;
|
|
10
|
+
messages?: Partial<AuthMessages>;
|
|
8
11
|
onSuccess?: () => void;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
let { apiBase = '/api/auth', onSuccess }: Props = $props();
|
|
14
|
+
let { apiBase = '/api/auth', locale, messages: messageOverrides, onSuccess }: Props = $props();
|
|
15
|
+
|
|
16
|
+
let m = $derived(resolveMessages(locale ?? detectLocaleClient(), messageOverrides));
|
|
12
17
|
|
|
13
18
|
let step = $state<1 | 2 | 3 | 4>(1);
|
|
14
19
|
let congratsTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -38,6 +43,8 @@ async function tryConditionalWebAuthn() {
|
|
|
38
43
|
optionsJSON: options,
|
|
39
44
|
useBrowserAutofill: true
|
|
40
45
|
});
|
|
46
|
+
// User selected a passkey — show loading while we verify
|
|
47
|
+
loading = true;
|
|
41
48
|
const verifyRes = await fetch(`${apiBase}/passkey/login-finish`, {
|
|
42
49
|
method: 'POST',
|
|
43
50
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -48,13 +55,15 @@ async function tryConditionalWebAuthn() {
|
|
|
48
55
|
}
|
|
49
56
|
} catch {
|
|
50
57
|
// Passkey autofill not available or cancelled
|
|
58
|
+
} finally {
|
|
59
|
+
loading = false;
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
async function handleEmailSubmit() {
|
|
55
64
|
error = '';
|
|
56
65
|
if (!email.includes('@')) {
|
|
57
|
-
error =
|
|
66
|
+
error = m.errorInvalidEmail;
|
|
58
67
|
return;
|
|
59
68
|
}
|
|
60
69
|
loading = true;
|
|
@@ -73,7 +82,7 @@ async function handleEmailSubmit() {
|
|
|
73
82
|
}
|
|
74
83
|
step = 2;
|
|
75
84
|
} catch {
|
|
76
|
-
error =
|
|
85
|
+
error = m.errorGeneric;
|
|
77
86
|
} finally {
|
|
78
87
|
loading = false;
|
|
79
88
|
}
|
|
@@ -90,7 +99,7 @@ async function handleOtpComplete(code: string) {
|
|
|
90
99
|
});
|
|
91
100
|
if (!res.ok) {
|
|
92
101
|
const data = await res.json().catch(() => null);
|
|
93
|
-
error = data?.error ??
|
|
102
|
+
error = data?.error ?? m.errorInvalidCode;
|
|
94
103
|
otpInput?.clear();
|
|
95
104
|
return;
|
|
96
105
|
}
|
|
@@ -101,7 +110,7 @@ async function handleOtpComplete(code: string) {
|
|
|
101
110
|
step = 3;
|
|
102
111
|
}
|
|
103
112
|
} catch {
|
|
104
|
-
error =
|
|
113
|
+
error = m.errorGeneric;
|
|
105
114
|
} finally {
|
|
106
115
|
loading = false;
|
|
107
116
|
}
|
|
@@ -118,12 +127,12 @@ async function resendCode() {
|
|
|
118
127
|
});
|
|
119
128
|
if (!res.ok) {
|
|
120
129
|
const data = await res.json().catch(() => null);
|
|
121
|
-
error = data?.error ??
|
|
130
|
+
error = data?.error ?? m.errorResendFailed;
|
|
122
131
|
return;
|
|
123
132
|
}
|
|
124
133
|
otpInput?.clear();
|
|
125
134
|
} catch {
|
|
126
|
-
error =
|
|
135
|
+
error = m.errorGeneric;
|
|
127
136
|
} finally {
|
|
128
137
|
loading = false;
|
|
129
138
|
}
|
|
@@ -166,7 +175,7 @@ function handlePasskeySkip() {
|
|
|
166
175
|
bind:value={email}
|
|
167
176
|
required
|
|
168
177
|
autocomplete="username webauthn"
|
|
169
|
-
placeholder=
|
|
178
|
+
placeholder={m.emailPlaceholder}
|
|
170
179
|
class="anahtar-input"
|
|
171
180
|
/>
|
|
172
181
|
|
|
@@ -175,12 +184,12 @@ function handlePasskeySkip() {
|
|
|
175
184
|
{/if}
|
|
176
185
|
|
|
177
186
|
<button type="submit" disabled={loading} class="anahtar-button">
|
|
178
|
-
{loading ? '...' :
|
|
187
|
+
{loading ? '...' : m.continue}
|
|
179
188
|
</button>
|
|
180
189
|
</form>
|
|
181
190
|
{:else if step === 2}
|
|
182
191
|
<div class="anahtar-otp-step">
|
|
183
|
-
<p class="anahtar-subtitle">
|
|
192
|
+
<p class="anahtar-subtitle">{m.codeSentTo}</p>
|
|
184
193
|
<p class="anahtar-email">{email}</p>
|
|
185
194
|
|
|
186
195
|
<OtpInput bind:this={otpInput} onComplete={handleOtpComplete} disabled={loading} />
|
|
@@ -190,12 +199,12 @@ function handlePasskeySkip() {
|
|
|
190
199
|
{/if}
|
|
191
200
|
|
|
192
201
|
{#if loading}
|
|
193
|
-
<p class="anahtar-subtitle">
|
|
202
|
+
<p class="anahtar-subtitle">{m.verifying}</p>
|
|
194
203
|
{/if}
|
|
195
204
|
|
|
196
205
|
<div class="anahtar-links">
|
|
197
206
|
<button onclick={resendCode} disabled={loading} class="anahtar-link">
|
|
198
|
-
|
|
207
|
+
{m.resend}
|
|
199
208
|
</button>
|
|
200
209
|
<button
|
|
201
210
|
onclick={() => {
|
|
@@ -204,12 +213,12 @@ function handlePasskeySkip() {
|
|
|
204
213
|
}}
|
|
205
214
|
class="anahtar-link"
|
|
206
215
|
>
|
|
207
|
-
|
|
216
|
+
{m.differentEmail}
|
|
208
217
|
</button>
|
|
209
218
|
</div>
|
|
210
219
|
</div>
|
|
211
220
|
{:else if step === 3}
|
|
212
|
-
<PasskeyPrompt onRegister={handlePasskeyRegister} onSkip={handlePasskeySkip} />
|
|
221
|
+
<PasskeyPrompt {m} onRegister={handlePasskeyRegister} onSkip={handlePasskeySkip} />
|
|
213
222
|
{:else if step === 4}
|
|
214
223
|
<div class="anahtar-congrats">
|
|
215
224
|
<div class="anahtar-congrats-icon">
|
|
@@ -220,9 +229,9 @@ function handlePasskeySkip() {
|
|
|
220
229
|
<path d="m17.5 4.5 2 2"/>
|
|
221
230
|
</svg>
|
|
222
231
|
</div>
|
|
223
|
-
<p class="anahtar-congrats-title">
|
|
232
|
+
<p class="anahtar-congrats-title">{m.passkeySuccess}</p>
|
|
224
233
|
<button onclick={() => onSuccess?.()} class="anahtar-button">
|
|
225
|
-
|
|
234
|
+
{m.continue}
|
|
226
235
|
</button>
|
|
227
236
|
</div>
|
|
228
237
|
{/if}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { AuthMessages } from '../i18n/types.js';
|
|
3
|
+
|
|
2
4
|
interface Props {
|
|
5
|
+
m: AuthMessages;
|
|
3
6
|
countdownSeconds?: number;
|
|
4
7
|
onRegister: () => Promise<void>;
|
|
5
8
|
onSkip: () => void;
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
let { countdownSeconds = 3, onRegister, onSkip }: Props = $props();
|
|
11
|
+
let { m, countdownSeconds = 3, onRegister, onSkip }: Props = $props();
|
|
9
12
|
|
|
10
13
|
let countdown = $state(countdownSeconds);
|
|
11
14
|
let failed = $state(false);
|
|
@@ -70,15 +73,15 @@ let dashOffset = $derived(circumference * (1 - countdown / countdownSeconds));
|
|
|
70
73
|
</div>
|
|
71
74
|
|
|
72
75
|
{#if !failed}
|
|
73
|
-
<p class="anahtar-passkey-title">
|
|
74
|
-
<p class="anahtar-passkey-subtitle">
|
|
75
|
-
<button onclick={onSkip} class="anahtar-passkey-skip">
|
|
76
|
+
<p class="anahtar-passkey-title">{m.passkeyCreating}</p>
|
|
77
|
+
<p class="anahtar-passkey-subtitle">{m.passkeySubtitle}</p>
|
|
78
|
+
<button onclick={onSkip} class="anahtar-passkey-skip">{m.passkeySkip}</button>
|
|
76
79
|
{:else}
|
|
77
|
-
<p class="anahtar-passkey-title">
|
|
80
|
+
<p class="anahtar-passkey-title">{m.passkeySetup}</p>
|
|
78
81
|
<button onclick={triggerRegistration} class="anahtar-passkey-add" disabled={registering}>
|
|
79
|
-
|
|
82
|
+
{m.passkeyAdd}
|
|
80
83
|
</button>
|
|
81
|
-
<button onclick={onSkip} class="anahtar-passkey-skip">
|
|
84
|
+
<button onclick={onSkip} class="anahtar-passkey-skip">{m.passkeyMaybeLater}</button>
|
|
82
85
|
{/if}
|
|
83
86
|
</div>
|
|
84
87
|
|
|
@@ -2,3 +2,5 @@ export { guessDeviceName } from '../device.js';
|
|
|
2
2
|
export { default as AuthFlow } from './AuthFlow.svelte';
|
|
3
3
|
export { default as OtpInput } from './OtpInput.svelte';
|
|
4
4
|
export { default as PasskeyPrompt } from './PasskeyPrompt.svelte';
|
|
5
|
+
export type { AuthMessages } from '../i18n/types.js';
|
|
6
|
+
export { resolveMessages, detectLocaleClient, locales } from '../i18n/index.js';
|
package/dist/components/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { guessDeviceName } from '../device.js';
|
|
|
2
2
|
export { default as AuthFlow } from './AuthFlow.svelte';
|
|
3
3
|
export { default as OtpInput } from './OtpInput.svelte';
|
|
4
4
|
export { default as PasskeyPrompt } from './PasskeyPrompt.svelte';
|
|
5
|
+
export { resolveMessages, detectLocaleClient, locales } from '../i18n/index.js';
|
package/dist/i18n/ar.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ar = {
|
|
2
|
+
emailPlaceholder: 'you@example.com',
|
|
3
|
+
continue: 'متابعة',
|
|
4
|
+
codeSentTo: 'أرسلنا رمزًا إلى',
|
|
5
|
+
verifying: 'جارٍ التحقق...',
|
|
6
|
+
resend: 'لم يصلك؟ إعادة الإرسال',
|
|
7
|
+
differentEmail: 'استخدام بريد إلكتروني آخر',
|
|
8
|
+
passkeyCreating: 'جارٍ إنشاء مفتاح المرور',
|
|
9
|
+
passkeySubtitle: 'لتسجيل دخول أسهل',
|
|
10
|
+
passkeySkip: 'تخطي',
|
|
11
|
+
passkeySetup: 'إعداد مفتاح مرور؟',
|
|
12
|
+
passkeyAdd: 'إضافة مفتاح مرور',
|
|
13
|
+
passkeyMaybeLater: 'ربما لاحقًا',
|
|
14
|
+
passkeySuccess: 'مفتاح المرور جاهز!',
|
|
15
|
+
errorInvalidEmail: 'يرجى إدخال بريد إلكتروني صالح.',
|
|
16
|
+
errorGeneric: 'حدث خطأ ما. يرجى المحاولة مرة أخرى.',
|
|
17
|
+
errorResendFailed: 'فشل إعادة إرسال الرمز.',
|
|
18
|
+
errorInvalidCode: 'رمز غير صالح. يرجى المحاولة مرة أخرى.',
|
|
19
|
+
errorCodeExpired: 'انتهت صلاحية الرمز. يرجى طلب رمز جديد.',
|
|
20
|
+
errorTooManyAttempts: 'محاولات كثيرة جدًا. يرجى طلب رمز جديد.',
|
|
21
|
+
errorInvalidInput: 'إدخال غير صالح',
|
|
22
|
+
errorNotAuthenticated: 'غير مسجل الدخول',
|
|
23
|
+
errorNotFound: 'غير موجود',
|
|
24
|
+
errorAuthFailed: 'فشل التحقق من الهوية',
|
|
25
|
+
errorPasskeyRegFailed: 'فشل تسجيل مفتاح المرور',
|
|
26
|
+
errorPasskeyNotFound: 'مفتاح المرور غير موجود',
|
|
27
|
+
};
|
|
28
|
+
export default ar;
|
package/dist/i18n/de.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const de = {
|
|
2
|
+
emailPlaceholder: 'du@beispiel.de',
|
|
3
|
+
continue: 'Weiter',
|
|
4
|
+
codeSentTo: 'Wir haben einen Code gesendet an',
|
|
5
|
+
verifying: 'Wird uberpruft...',
|
|
6
|
+
resend: 'Nicht erhalten? Erneut senden',
|
|
7
|
+
differentEmail: 'Andere E-Mail verwenden',
|
|
8
|
+
passkeyCreating: 'Passkey wird erstellt',
|
|
9
|
+
passkeySubtitle: 'fur einfacheres Anmelden',
|
|
10
|
+
passkeySkip: 'Uberspringen',
|
|
11
|
+
passkeySetup: 'Passkey einrichten?',
|
|
12
|
+
passkeyAdd: 'Passkey hinzufugen',
|
|
13
|
+
passkeyMaybeLater: 'Vielleicht spater',
|
|
14
|
+
passkeySuccess: 'Dein Passkey ist bereit!',
|
|
15
|
+
errorInvalidEmail: 'Bitte gib eine gultige E-Mail-Adresse ein.',
|
|
16
|
+
errorGeneric: 'Etwas ist schiefgelaufen. Bitte versuche es erneut.',
|
|
17
|
+
errorResendFailed: 'Code konnte nicht erneut gesendet werden.',
|
|
18
|
+
errorInvalidCode: 'Ungueltiger Code. Bitte versuche es erneut.',
|
|
19
|
+
errorCodeExpired: 'Code abgelaufen. Bitte fordere einen neuen an.',
|
|
20
|
+
errorTooManyAttempts: 'Zu viele Versuche. Bitte fordere einen neuen Code an.',
|
|
21
|
+
errorInvalidInput: 'Ungueltige Eingabe',
|
|
22
|
+
errorNotAuthenticated: 'Nicht authentifiziert',
|
|
23
|
+
errorNotFound: 'Nicht gefunden',
|
|
24
|
+
errorAuthFailed: 'Authentifizierung fehlgeschlagen',
|
|
25
|
+
errorPasskeyRegFailed: 'Passkey-Registrierung fehlgeschlagen',
|
|
26
|
+
errorPasskeyNotFound: 'Passkey nicht gefunden',
|
|
27
|
+
};
|
|
28
|
+
export default de;
|
package/dist/i18n/en.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const en = {
|
|
2
|
+
emailPlaceholder: 'you@example.com',
|
|
3
|
+
continue: 'Continue',
|
|
4
|
+
codeSentTo: 'We sent a code to',
|
|
5
|
+
verifying: 'Verifying...',
|
|
6
|
+
resend: "Didn't get it? Resend",
|
|
7
|
+
differentEmail: 'Use a different email',
|
|
8
|
+
passkeyCreating: 'Making you a passkey',
|
|
9
|
+
passkeySubtitle: 'for easier login',
|
|
10
|
+
passkeySkip: 'Skip',
|
|
11
|
+
passkeySetup: 'Set up a passkey?',
|
|
12
|
+
passkeyAdd: 'Add passkey',
|
|
13
|
+
passkeyMaybeLater: 'Maybe later',
|
|
14
|
+
passkeySuccess: "You've got a passkey!",
|
|
15
|
+
errorInvalidEmail: 'Please enter a valid email address.',
|
|
16
|
+
errorGeneric: 'Something went wrong. Please try again.',
|
|
17
|
+
errorResendFailed: 'Failed to resend code.',
|
|
18
|
+
errorInvalidCode: 'Invalid code. Please try again.',
|
|
19
|
+
errorCodeExpired: 'Code expired. Please request a new one.',
|
|
20
|
+
errorTooManyAttempts: 'Too many attempts. Please request a new code.',
|
|
21
|
+
errorInvalidInput: 'Invalid input',
|
|
22
|
+
errorNotAuthenticated: 'Not authenticated',
|
|
23
|
+
errorNotFound: 'Not found',
|
|
24
|
+
errorAuthFailed: 'Authentication failed',
|
|
25
|
+
errorPasskeyRegFailed: 'Passkey registration failed',
|
|
26
|
+
errorPasskeyNotFound: 'Passkey not found',
|
|
27
|
+
};
|
|
28
|
+
export default en;
|
package/dist/i18n/es.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const es = {
|
|
2
|
+
emailPlaceholder: 'tu@ejemplo.com',
|
|
3
|
+
continue: 'Continuar',
|
|
4
|
+
codeSentTo: 'Enviamos un codigo a',
|
|
5
|
+
verifying: 'Verificando...',
|
|
6
|
+
resend: 'No lo recibiste? Reenviar',
|
|
7
|
+
differentEmail: 'Usar otro correo',
|
|
8
|
+
passkeyCreating: 'Creando tu passkey',
|
|
9
|
+
passkeySubtitle: 'para iniciar sesion mas facil',
|
|
10
|
+
passkeySkip: 'Omitir',
|
|
11
|
+
passkeySetup: 'Configurar passkey?',
|
|
12
|
+
passkeyAdd: 'Agregar passkey',
|
|
13
|
+
passkeyMaybeLater: 'Quiza despues',
|
|
14
|
+
passkeySuccess: 'Ya tienes tu passkey!',
|
|
15
|
+
errorInvalidEmail: 'Ingresa un correo electronico valido.',
|
|
16
|
+
errorGeneric: 'Algo salio mal. Intenta de nuevo.',
|
|
17
|
+
errorResendFailed: 'No se pudo reenviar el codigo.',
|
|
18
|
+
errorInvalidCode: 'Codigo invalido. Intenta de nuevo.',
|
|
19
|
+
errorCodeExpired: 'El codigo expiro. Solicita uno nuevo.',
|
|
20
|
+
errorTooManyAttempts: 'Demasiados intentos. Solicita un nuevo codigo.',
|
|
21
|
+
errorInvalidInput: 'Entrada invalida',
|
|
22
|
+
errorNotAuthenticated: 'No autenticado',
|
|
23
|
+
errorNotFound: 'No encontrado',
|
|
24
|
+
errorAuthFailed: 'Fallo la autenticacion',
|
|
25
|
+
errorPasskeyRegFailed: 'Fallo el registro del passkey',
|
|
26
|
+
errorPasskeyNotFound: 'Passkey no encontrado',
|
|
27
|
+
};
|
|
28
|
+
export default es;
|
package/dist/i18n/fr.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fr = {
|
|
2
|
+
emailPlaceholder: 'vous@exemple.com',
|
|
3
|
+
continue: 'Continuer',
|
|
4
|
+
codeSentTo: 'Nous avons envoye un code a',
|
|
5
|
+
verifying: 'Verification...',
|
|
6
|
+
resend: 'Pas recu ? Renvoyer',
|
|
7
|
+
differentEmail: 'Utiliser un autre e-mail',
|
|
8
|
+
passkeyCreating: 'Creation de votre passkey',
|
|
9
|
+
passkeySubtitle: 'pour une connexion plus facile',
|
|
10
|
+
passkeySkip: 'Passer',
|
|
11
|
+
passkeySetup: 'Configurer un passkey ?',
|
|
12
|
+
passkeyAdd: 'Ajouter un passkey',
|
|
13
|
+
passkeyMaybeLater: 'Plus tard',
|
|
14
|
+
passkeySuccess: 'Votre passkey est pret !',
|
|
15
|
+
errorInvalidEmail: 'Veuillez entrer une adresse e-mail valide.',
|
|
16
|
+
errorGeneric: 'Une erreur est survenue. Veuillez reessayer.',
|
|
17
|
+
errorResendFailed: "Echec de l'envoi du code.",
|
|
18
|
+
errorInvalidCode: 'Code invalide. Veuillez reessayer.',
|
|
19
|
+
errorCodeExpired: 'Code expire. Veuillez en demander un nouveau.',
|
|
20
|
+
errorTooManyAttempts: 'Trop de tentatives. Veuillez demander un nouveau code.',
|
|
21
|
+
errorInvalidInput: 'Entree invalide',
|
|
22
|
+
errorNotAuthenticated: 'Non authentifie',
|
|
23
|
+
errorNotFound: 'Non trouve',
|
|
24
|
+
errorAuthFailed: "Echec de l'authentification",
|
|
25
|
+
errorPasskeyRegFailed: "Echec de l'enregistrement du passkey",
|
|
26
|
+
errorPasskeyNotFound: 'Passkey introuvable',
|
|
27
|
+
};
|
|
28
|
+
export default fr;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AuthMessages } from './types.js';
|
|
2
|
+
export type { AuthMessages } from './types.js';
|
|
3
|
+
export { default as en } from './en.js';
|
|
4
|
+
export declare const locales: Record<string, AuthMessages>;
|
|
5
|
+
export declare function resolveMessages(locale?: string, overrides?: Partial<AuthMessages>): AuthMessages;
|
|
6
|
+
export declare function detectLocaleClient(): string;
|
|
7
|
+
export declare function detectLocaleServer(request: Request): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import en from './en.js';
|
|
2
|
+
import ar from './ar.js';
|
|
3
|
+
import de from './de.js';
|
|
4
|
+
import es from './es.js';
|
|
5
|
+
import fr from './fr.js';
|
|
6
|
+
import ja from './ja.js';
|
|
7
|
+
import ko from './ko.js';
|
|
8
|
+
import pt from './pt.js';
|
|
9
|
+
import tr from './tr.js';
|
|
10
|
+
import zh from './zh.js';
|
|
11
|
+
export { default as en } from './en.js';
|
|
12
|
+
export const locales = {
|
|
13
|
+
en,
|
|
14
|
+
ar,
|
|
15
|
+
de,
|
|
16
|
+
es,
|
|
17
|
+
fr,
|
|
18
|
+
ja,
|
|
19
|
+
ko,
|
|
20
|
+
pt,
|
|
21
|
+
tr,
|
|
22
|
+
zh,
|
|
23
|
+
};
|
|
24
|
+
export function resolveMessages(locale, overrides) {
|
|
25
|
+
const lang = locale?.split('-')[0]?.toLowerCase();
|
|
26
|
+
const base = (lang && locales[lang]) || en;
|
|
27
|
+
return overrides ? { ...base, ...overrides } : base;
|
|
28
|
+
}
|
|
29
|
+
export function detectLocaleClient() {
|
|
30
|
+
if (typeof navigator !== 'undefined') {
|
|
31
|
+
return navigator.language?.split('-')[0] ?? 'en';
|
|
32
|
+
}
|
|
33
|
+
return 'en';
|
|
34
|
+
}
|
|
35
|
+
export function detectLocaleServer(request) {
|
|
36
|
+
const header = request.headers.get('accept-language');
|
|
37
|
+
if (!header)
|
|
38
|
+
return 'en';
|
|
39
|
+
const first = header.split(',')[0];
|
|
40
|
+
return first?.split('-')[0]?.trim() ?? 'en';
|
|
41
|
+
}
|
package/dist/i18n/ja.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ja = {
|
|
2
|
+
emailPlaceholder: 'you@example.com',
|
|
3
|
+
continue: '続ける',
|
|
4
|
+
codeSentTo: '確認コードを送信しました:',
|
|
5
|
+
verifying: '確認中...',
|
|
6
|
+
resend: '届きませんか?再送信',
|
|
7
|
+
differentEmail: '別のメールアドレスを使用',
|
|
8
|
+
passkeyCreating: 'パスキーを作成中',
|
|
9
|
+
passkeySubtitle: 'より簡単にログイン',
|
|
10
|
+
passkeySkip: 'スキップ',
|
|
11
|
+
passkeySetup: 'パスキーを設定しますか?',
|
|
12
|
+
passkeyAdd: 'パスキーを追加',
|
|
13
|
+
passkeyMaybeLater: 'あとで',
|
|
14
|
+
passkeySuccess: 'パスキーの準備ができました!',
|
|
15
|
+
errorInvalidEmail: '有効なメールアドレスを入力してください。',
|
|
16
|
+
errorGeneric: 'エラーが発生しました。もう一度お試しください。',
|
|
17
|
+
errorResendFailed: 'コードの再送信に失敗しました。',
|
|
18
|
+
errorInvalidCode: '無効なコードです。もう一度お試しください。',
|
|
19
|
+
errorCodeExpired: 'コードの有効期限が切れました。新しいコードをリクエストしてください。',
|
|
20
|
+
errorTooManyAttempts: '試行回数が多すぎます。新しいコードをリクエストしてください。',
|
|
21
|
+
errorInvalidInput: '無効な入力',
|
|
22
|
+
errorNotAuthenticated: '未認証',
|
|
23
|
+
errorNotFound: '見つかりません',
|
|
24
|
+
errorAuthFailed: '認証に失敗しました',
|
|
25
|
+
errorPasskeyRegFailed: 'パスキーの登録に失敗しました',
|
|
26
|
+
errorPasskeyNotFound: 'パスキーが見つかりません',
|
|
27
|
+
};
|
|
28
|
+
export default ja;
|
package/dist/i18n/ko.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ko = {
|
|
2
|
+
emailPlaceholder: 'you@example.com',
|
|
3
|
+
continue: '계속',
|
|
4
|
+
codeSentTo: '인증 코드를 보냈습니다:',
|
|
5
|
+
verifying: '확인 중...',
|
|
6
|
+
resend: '받지 못하셨나요? 다시 보내기',
|
|
7
|
+
differentEmail: '다른 이메일 사용',
|
|
8
|
+
passkeyCreating: '패스키 생성 중',
|
|
9
|
+
passkeySubtitle: '더 쉬운 로그인을 위해',
|
|
10
|
+
passkeySkip: '건너뛰기',
|
|
11
|
+
passkeySetup: '패스키를 설정할까요?',
|
|
12
|
+
passkeyAdd: '패스키 추가',
|
|
13
|
+
passkeyMaybeLater: '나중에',
|
|
14
|
+
passkeySuccess: '패스키가 준비되었습니다!',
|
|
15
|
+
errorInvalidEmail: '유효한 이메일 주소를 입력해주세요.',
|
|
16
|
+
errorGeneric: '문제가 발생했습니다. 다시 시도해주세요.',
|
|
17
|
+
errorResendFailed: '코드 재전송에 실패했습니다.',
|
|
18
|
+
errorInvalidCode: '잘못된 코드입니다. 다시 시도해주세요.',
|
|
19
|
+
errorCodeExpired: '코드가 만료되었습니다. 새 코드를 요청해주세요.',
|
|
20
|
+
errorTooManyAttempts: '시도 횟수가 너무 많습니다. 새 코드를 요청해주세요.',
|
|
21
|
+
errorInvalidInput: '잘못된 입력',
|
|
22
|
+
errorNotAuthenticated: '인증되지 않음',
|
|
23
|
+
errorNotFound: '찾을 수 없음',
|
|
24
|
+
errorAuthFailed: '인증 실패',
|
|
25
|
+
errorPasskeyRegFailed: '패스키 등록 실패',
|
|
26
|
+
errorPasskeyNotFound: '패스키를 찾을 수 없음',
|
|
27
|
+
};
|
|
28
|
+
export default ko;
|
package/dist/i18n/pt.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const pt = {
|
|
2
|
+
emailPlaceholder: 'voce@exemplo.com',
|
|
3
|
+
continue: 'Continuar',
|
|
4
|
+
codeSentTo: 'Enviamos um codigo para',
|
|
5
|
+
verifying: 'Verificando...',
|
|
6
|
+
resend: 'Nao recebeu? Reenviar',
|
|
7
|
+
differentEmail: 'Usar outro e-mail',
|
|
8
|
+
passkeyCreating: 'Criando sua passkey',
|
|
9
|
+
passkeySubtitle: 'para login mais facil',
|
|
10
|
+
passkeySkip: 'Pular',
|
|
11
|
+
passkeySetup: 'Configurar passkey?',
|
|
12
|
+
passkeyAdd: 'Adicionar passkey',
|
|
13
|
+
passkeyMaybeLater: 'Talvez depois',
|
|
14
|
+
passkeySuccess: 'Sua passkey esta pronta!',
|
|
15
|
+
errorInvalidEmail: 'Digite um endereco de e-mail valido.',
|
|
16
|
+
errorGeneric: 'Algo deu errado. Tente novamente.',
|
|
17
|
+
errorResendFailed: 'Falha ao reenviar o codigo.',
|
|
18
|
+
errorInvalidCode: 'Codigo invalido. Tente novamente.',
|
|
19
|
+
errorCodeExpired: 'Codigo expirado. Solicite um novo.',
|
|
20
|
+
errorTooManyAttempts: 'Muitas tentativas. Solicite um novo codigo.',
|
|
21
|
+
errorInvalidInput: 'Entrada invalida',
|
|
22
|
+
errorNotAuthenticated: 'Nao autenticado',
|
|
23
|
+
errorNotFound: 'Nao encontrado',
|
|
24
|
+
errorAuthFailed: 'Falha na autenticacao',
|
|
25
|
+
errorPasskeyRegFailed: 'Falha no registro da passkey',
|
|
26
|
+
errorPasskeyNotFound: 'Passkey nao encontrada',
|
|
27
|
+
};
|
|
28
|
+
export default pt;
|
package/dist/i18n/tr.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const tr = {
|
|
2
|
+
emailPlaceholder: 'sen@ornek.com',
|
|
3
|
+
continue: 'Devam',
|
|
4
|
+
codeSentTo: 'Kod gonderildi:',
|
|
5
|
+
verifying: 'Dogrulanıyor...',
|
|
6
|
+
resend: 'Almadın mı? Tekrar gonder',
|
|
7
|
+
differentEmail: 'Baska e-posta kullan',
|
|
8
|
+
passkeyCreating: 'Anahtar olusturuluyor',
|
|
9
|
+
passkeySubtitle: 'daha kolay giris icin',
|
|
10
|
+
passkeySkip: 'Atla',
|
|
11
|
+
passkeySetup: 'Anahtar olustur?',
|
|
12
|
+
passkeyAdd: 'Anahtar ekle',
|
|
13
|
+
passkeyMaybeLater: 'Belki sonra',
|
|
14
|
+
passkeySuccess: 'Anahtarın hazır!',
|
|
15
|
+
errorInvalidEmail: 'Gecerli bir e-posta adresi girin.',
|
|
16
|
+
errorGeneric: 'Bir hata olustu. Lutfen tekrar deneyin.',
|
|
17
|
+
errorResendFailed: 'Kod tekrar gonderilemedi.',
|
|
18
|
+
errorInvalidCode: 'Gecersiz kod. Lutfen tekrar deneyin.',
|
|
19
|
+
errorCodeExpired: 'Kodun suresi doldu. Yeni bir kod isteyin.',
|
|
20
|
+
errorTooManyAttempts: 'Cok fazla deneme. Yeni bir kod isteyin.',
|
|
21
|
+
errorInvalidInput: 'Gecersiz giris',
|
|
22
|
+
errorNotAuthenticated: 'Kimlik dogrulanmadı',
|
|
23
|
+
errorNotFound: 'Bulunamadı',
|
|
24
|
+
errorAuthFailed: 'Kimlik dogrulama basarısız',
|
|
25
|
+
errorPasskeyRegFailed: 'Anahtar kaydı basarısız',
|
|
26
|
+
errorPasskeyNotFound: 'Anahtar bulunamadı',
|
|
27
|
+
};
|
|
28
|
+
export default tr;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface AuthMessages {
|
|
2
|
+
emailPlaceholder: string;
|
|
3
|
+
continue: string;
|
|
4
|
+
codeSentTo: string;
|
|
5
|
+
verifying: string;
|
|
6
|
+
resend: string;
|
|
7
|
+
differentEmail: string;
|
|
8
|
+
passkeyCreating: string;
|
|
9
|
+
passkeySubtitle: string;
|
|
10
|
+
passkeySkip: string;
|
|
11
|
+
passkeySetup: string;
|
|
12
|
+
passkeyAdd: string;
|
|
13
|
+
passkeyMaybeLater: string;
|
|
14
|
+
passkeySuccess: string;
|
|
15
|
+
errorInvalidEmail: string;
|
|
16
|
+
errorGeneric: string;
|
|
17
|
+
errorResendFailed: string;
|
|
18
|
+
errorInvalidCode: string;
|
|
19
|
+
errorCodeExpired: string;
|
|
20
|
+
errorTooManyAttempts: string;
|
|
21
|
+
errorInvalidInput: string;
|
|
22
|
+
errorNotAuthenticated: string;
|
|
23
|
+
errorNotFound: string;
|
|
24
|
+
errorAuthFailed: string;
|
|
25
|
+
errorPasskeyRegFailed: string;
|
|
26
|
+
errorPasskeyNotFound: string;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/i18n/zh.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const zh = {
|
|
2
|
+
emailPlaceholder: 'you@example.com',
|
|
3
|
+
continue: '继续',
|
|
4
|
+
codeSentTo: '验证码已发送至',
|
|
5
|
+
verifying: '验证中...',
|
|
6
|
+
resend: '没收到?重新发送',
|
|
7
|
+
differentEmail: '使用其他邮箱',
|
|
8
|
+
passkeyCreating: '正在创建通行密钥',
|
|
9
|
+
passkeySubtitle: '更便捷的登录方式',
|
|
10
|
+
passkeySkip: '跳过',
|
|
11
|
+
passkeySetup: '设置通行密钥?',
|
|
12
|
+
passkeyAdd: '添加通行密钥',
|
|
13
|
+
passkeyMaybeLater: '以后再说',
|
|
14
|
+
passkeySuccess: '通行密钥已就绪!',
|
|
15
|
+
errorInvalidEmail: '请输入有效的电子邮箱地址。',
|
|
16
|
+
errorGeneric: '出了点问题,请重试。',
|
|
17
|
+
errorResendFailed: '重新发送失败。',
|
|
18
|
+
errorInvalidCode: '验证码无效,请重试。',
|
|
19
|
+
errorCodeExpired: '验证码已过期,请重新获取。',
|
|
20
|
+
errorTooManyAttempts: '尝试次数过多,请重新获取验证码。',
|
|
21
|
+
errorInvalidInput: '输入无效',
|
|
22
|
+
errorNotAuthenticated: '未登录',
|
|
23
|
+
errorNotFound: '未找到',
|
|
24
|
+
errorAuthFailed: '身份验证失败',
|
|
25
|
+
errorPasskeyRegFailed: '通行密钥注册失败',
|
|
26
|
+
errorPasskeyNotFound: '未找到通行密钥',
|
|
27
|
+
};
|
|
28
|
+
export default zh;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { AuthConfig } from './types.js';
|
|
|
2
2
|
export { resolveConfig } from './config.js';
|
|
3
3
|
export { guessDeviceName } from './device.js';
|
|
4
4
|
export type { AuthConfig, AuthDB, AuthUser, FullPasskeyRecord, MaybePromise, NewPasskey, OTPRecord, OtpResult, PasskeyRecord, ResolvedConfig, SessionRecord } from './types.js';
|
|
5
|
+
export type { AuthMessages } from './i18n/types.js';
|
|
6
|
+
export { resolveMessages, detectLocaleClient, detectLocaleServer, locales } from './i18n/index.js';
|
|
5
7
|
export declare function createAuth(config: AuthConfig): Promise<{
|
|
6
8
|
handle: import("@sveltejs/kit").Handle;
|
|
7
9
|
handlers: {
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createHandle } from './kit/handle.js';
|
|
|
3
3
|
import { createHandlers } from './kit/handlers.js';
|
|
4
4
|
export { resolveConfig } from './config.js';
|
|
5
5
|
export { guessDeviceName } from './device.js';
|
|
6
|
+
export { resolveMessages, detectLocaleClient, detectLocaleServer, locales } from './i18n/index.js';
|
|
6
7
|
export async function createAuth(config) {
|
|
7
8
|
const resolved = resolveConfig(config);
|
|
8
9
|
await config.db.init();
|
package/dist/kit/handlers.js
CHANGED
|
@@ -2,11 +2,16 @@ import { json } from '@sveltejs/kit';
|
|
|
2
2
|
import { generateOTP, verifyOTP } from '../otp.js';
|
|
3
3
|
import { generateAuthenticationChallenge, generateRegistrationChallenge, removePasskey, verifyAuthenticationResponse, verifyRegistrationResponse } from '../passkey.js';
|
|
4
4
|
import { createSession, invalidateSession, validateSession } from '../session.js';
|
|
5
|
+
import { resolveMessages, detectLocaleServer } from '../i18n/index.js';
|
|
5
6
|
const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
|
|
6
|
-
function
|
|
7
|
+
function getMessages(event, config) {
|
|
8
|
+
const locale = config.locale ?? detectLocaleServer(event.request);
|
|
9
|
+
return resolveMessages(locale, config.messages);
|
|
10
|
+
}
|
|
11
|
+
function requireAuth(event, m) {
|
|
7
12
|
const user = event.locals.user;
|
|
8
13
|
if (!user)
|
|
9
|
-
return json({ error:
|
|
14
|
+
return json({ error: m.errorNotAuthenticated }, { status: 401 });
|
|
10
15
|
return user;
|
|
11
16
|
}
|
|
12
17
|
export function createHandlers(config) {
|
|
@@ -24,9 +29,10 @@ export function createHandlers(config) {
|
|
|
24
29
|
start: {
|
|
25
30
|
method: 'POST',
|
|
26
31
|
handler: async (event) => {
|
|
32
|
+
const m = getMessages(event, config);
|
|
27
33
|
const body = await event.request.json().catch(() => null);
|
|
28
34
|
if (!body || typeof body.email !== 'string' || !body.email.includes('@')) {
|
|
29
|
-
return json({ error:
|
|
35
|
+
return json({ error: m.errorInvalidEmail }, { status: 400 });
|
|
30
36
|
}
|
|
31
37
|
const { code } = await generateOTP(config.db, body.email, config);
|
|
32
38
|
await config.onSendOTP(body.email, code);
|
|
@@ -36,16 +42,17 @@ export function createHandlers(config) {
|
|
|
36
42
|
verify: {
|
|
37
43
|
method: 'POST',
|
|
38
44
|
handler: async (event) => {
|
|
45
|
+
const m = getMessages(event, config);
|
|
39
46
|
const body = await event.request.json().catch(() => null);
|
|
40
47
|
if (!body || typeof body.email !== 'string' || typeof body.code !== 'string') {
|
|
41
|
-
return json({ error:
|
|
48
|
+
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
42
49
|
}
|
|
43
50
|
const otp = await verifyOTP(config.db, body.email, body.code, config);
|
|
44
51
|
if (!otp.ok) {
|
|
45
52
|
const messages = {
|
|
46
|
-
invalid:
|
|
47
|
-
expired:
|
|
48
|
-
rate_limited:
|
|
53
|
+
invalid: m.errorInvalidCode,
|
|
54
|
+
expired: m.errorCodeExpired,
|
|
55
|
+
rate_limited: m.errorTooManyAttempts,
|
|
49
56
|
};
|
|
50
57
|
return json({ error: messages[otp.error] }, { status: otp.error === 'rate_limited' ? 429 : 400 });
|
|
51
58
|
}
|
|
@@ -87,12 +94,13 @@ export function createHandlers(config) {
|
|
|
87
94
|
'passkey/login-finish': {
|
|
88
95
|
method: 'POST',
|
|
89
96
|
handler: async (event) => {
|
|
97
|
+
const m = getMessages(event, config);
|
|
90
98
|
const body = await event.request.json().catch(() => null);
|
|
91
99
|
if (!body)
|
|
92
|
-
return json({ error:
|
|
100
|
+
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
93
101
|
const result = await verifyAuthenticationResponse(config.db, body, event.url);
|
|
94
102
|
if (!result)
|
|
95
|
-
return json({ error:
|
|
103
|
+
return json({ error: m.errorAuthFailed }, { status: 401 });
|
|
96
104
|
const session = await createSession(config.db, result.user.id, config);
|
|
97
105
|
event.cookies.set(config.cookie, session.sessionToken, cookieOpts(event));
|
|
98
106
|
return json({ user: result.user });
|
|
@@ -101,7 +109,8 @@ export function createHandlers(config) {
|
|
|
101
109
|
'passkey/register-start': {
|
|
102
110
|
method: 'POST',
|
|
103
111
|
handler: async (event) => {
|
|
104
|
-
const
|
|
112
|
+
const m = getMessages(event, config);
|
|
113
|
+
const user = requireAuth(event, m);
|
|
105
114
|
if (user instanceof Response)
|
|
106
115
|
return user;
|
|
107
116
|
const options = await generateRegistrationChallenge(config.db, user, event.url, config);
|
|
@@ -111,18 +120,19 @@ export function createHandlers(config) {
|
|
|
111
120
|
'passkey/register-finish': {
|
|
112
121
|
method: 'POST',
|
|
113
122
|
handler: async (event) => {
|
|
114
|
-
const
|
|
123
|
+
const m = getMessages(event, config);
|
|
124
|
+
const user = requireAuth(event, m);
|
|
115
125
|
if (user instanceof Response)
|
|
116
126
|
return user;
|
|
117
127
|
const body = await event.request.json().catch(() => null);
|
|
118
128
|
if (!body)
|
|
119
|
-
return json({ error:
|
|
129
|
+
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
120
130
|
const { name, ...response } = body;
|
|
121
131
|
const passkeyName = typeof name === 'string' && name.trim() ? name.trim() : null;
|
|
122
132
|
const result = await verifyRegistrationResponse(config.db, user.id, response, event.url, passkeyName);
|
|
123
133
|
if (!result.ok) {
|
|
124
134
|
console.error('register-finish failed:', result.reason);
|
|
125
|
-
return json({ error:
|
|
135
|
+
return json({ error: m.errorPasskeyRegFailed, reason: result.reason }, { status: 400 });
|
|
126
136
|
}
|
|
127
137
|
return json({ success: true });
|
|
128
138
|
}
|
|
@@ -130,23 +140,25 @@ export function createHandlers(config) {
|
|
|
130
140
|
'passkey/remove': {
|
|
131
141
|
method: 'POST',
|
|
132
142
|
handler: async (event) => {
|
|
133
|
-
const
|
|
143
|
+
const m = getMessages(event, config);
|
|
144
|
+
const user = requireAuth(event, m);
|
|
134
145
|
if (user instanceof Response)
|
|
135
146
|
return user;
|
|
136
147
|
const body = await event.request.json().catch(() => null);
|
|
137
148
|
if (!body || typeof body.passkeyId !== 'string') {
|
|
138
|
-
return json({ error:
|
|
149
|
+
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
139
150
|
}
|
|
140
151
|
const success = await removePasskey(config.db, body.passkeyId, user.id);
|
|
141
152
|
if (!success)
|
|
142
|
-
return json({ error:
|
|
153
|
+
return json({ error: m.errorPasskeyNotFound }, { status: 404 });
|
|
143
154
|
return json({ success: true });
|
|
144
155
|
}
|
|
145
156
|
},
|
|
146
157
|
'skip-passkey': {
|
|
147
158
|
method: 'POST',
|
|
148
159
|
handler: async (event) => {
|
|
149
|
-
const
|
|
160
|
+
const m = getMessages(event, config);
|
|
161
|
+
const user = requireAuth(event, m);
|
|
150
162
|
if (user instanceof Response)
|
|
151
163
|
return user;
|
|
152
164
|
await config.db.setSkipPasskeyPrompt(user.id, true);
|
|
@@ -162,22 +174,24 @@ export function createHandlers(config) {
|
|
|
162
174
|
}
|
|
163
175
|
return {
|
|
164
176
|
GET: async (event) => {
|
|
177
|
+
const m = getMessages(event, config);
|
|
165
178
|
const path = getRoute(event);
|
|
166
179
|
if (!path)
|
|
167
|
-
return json({ error:
|
|
180
|
+
return json({ error: m.errorNotFound }, { status: 404 });
|
|
168
181
|
const route = routes[path];
|
|
169
182
|
if (!route || route.method !== 'GET') {
|
|
170
|
-
return json({ error:
|
|
183
|
+
return json({ error: m.errorNotFound }, { status: 404 });
|
|
171
184
|
}
|
|
172
185
|
return route.handler(event);
|
|
173
186
|
},
|
|
174
187
|
POST: async (event) => {
|
|
188
|
+
const m = getMessages(event, config);
|
|
175
189
|
const path = getRoute(event);
|
|
176
190
|
if (!path)
|
|
177
|
-
return json({ error:
|
|
191
|
+
return json({ error: m.errorNotFound }, { status: 404 });
|
|
178
192
|
const route = routes[path];
|
|
179
193
|
if (!route || route.method !== 'POST') {
|
|
180
|
-
return json({ error:
|
|
194
|
+
return json({ error: m.errorNotFound }, { status: 404 });
|
|
181
195
|
}
|
|
182
196
|
return route.handler(event);
|
|
183
197
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -86,8 +86,12 @@ export interface AuthConfig {
|
|
|
86
86
|
otpLength?: number;
|
|
87
87
|
otpMaxAttempts?: number;
|
|
88
88
|
rpName?: string;
|
|
89
|
+
locale?: string;
|
|
90
|
+
messages?: Partial<import('./i18n/types.js').AuthMessages>;
|
|
89
91
|
onSendOTP: (email: string, code: string) => Promise<void>;
|
|
90
92
|
}
|
|
91
|
-
export interface ResolvedConfig extends Required<Omit<AuthConfig, 'onSendOTP'>> {
|
|
93
|
+
export interface ResolvedConfig extends Required<Omit<AuthConfig, 'onSendOTP' | 'locale' | 'messages'>> {
|
|
94
|
+
locale?: string;
|
|
95
|
+
messages?: Partial<import('./i18n/types.js').AuthMessages>;
|
|
92
96
|
onSendOTP: (email: string, code: string) => Promise<void>;
|
|
93
97
|
}
|
package/package.json
CHANGED
|
@@ -1,92 +1,92 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
2
|
+
"name": "@mrgnw/anahtar",
|
|
3
|
+
"version": "0.0.12",
|
|
4
|
+
"description": "Opinionated, reusable auth for SvelteKit. Email+OTP + passkeys.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/mrgnw/anahtar.git"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"registry": "https://registry.npmjs.org/",
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "svelte-package",
|
|
17
|
+
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
18
|
+
"test": "vitest run --config vitest.unit.ts && vitest run --config vitest.browser.ts",
|
|
19
|
+
"test:unit": "vitest run --config vitest.unit.ts",
|
|
20
|
+
"test:browser": "vitest run --config vitest.browser.ts",
|
|
21
|
+
"prepublishOnly": "pnpm build"
|
|
22
|
+
},
|
|
23
|
+
"svelte": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"svelte": "./dist/index.js",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./sqlite": {
|
|
32
|
+
"types": "./dist/db/sqlite.d.ts",
|
|
33
|
+
"default": "./dist/db/sqlite.js"
|
|
34
|
+
},
|
|
35
|
+
"./postgres": {
|
|
36
|
+
"types": "./dist/db/postgres.d.ts",
|
|
37
|
+
"default": "./dist/db/postgres.js"
|
|
38
|
+
},
|
|
39
|
+
"./d1": {
|
|
40
|
+
"types": "./dist/db/d1.d.ts",
|
|
41
|
+
"default": "./dist/db/d1.js"
|
|
42
|
+
},
|
|
43
|
+
"./components": {
|
|
44
|
+
"types": "./dist/components/index.d.ts",
|
|
45
|
+
"svelte": "./dist/components/index.js",
|
|
46
|
+
"default": "./dist/components/index.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"!dist/**/*.test.*"
|
|
52
|
+
],
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@simplewebauthn/browser": "^13.0.0",
|
|
55
|
+
"@sveltejs/kit": "^2.0.0",
|
|
56
|
+
"svelte": "^5.0.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"svelte": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"@simplewebauthn/browser": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@oslojs/crypto": "^1.0.1",
|
|
68
|
+
"@oslojs/encoding": "^1.1.0",
|
|
69
|
+
"@simplewebauthn/server": "^13.2.2"
|
|
70
|
+
},
|
|
71
|
+
"pnpm": {
|
|
72
|
+
"onlyBuiltDependencies": [
|
|
73
|
+
"better-sqlite3"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@simplewebauthn/browser": "^13.2.2",
|
|
78
|
+
"@sveltejs/kit": "^2.31.1",
|
|
79
|
+
"@sveltejs/package": "^2.3.7",
|
|
80
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
81
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
82
|
+
"@testing-library/svelte": "^5.3.1",
|
|
83
|
+
"@testing-library/user-event": "^14.6.1",
|
|
84
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
85
|
+
"better-sqlite3": "^12.6.2",
|
|
86
|
+
"happy-dom": "^20.6.1",
|
|
87
|
+
"svelte": "^5.38.1",
|
|
88
|
+
"svelte-check": "^4.3.1",
|
|
89
|
+
"typescript": "^5.9.2",
|
|
90
|
+
"vitest": "^3.2.1"
|
|
91
|
+
}
|
|
92
92
|
}
|