@vonall/auth 0.3.0 → 0.4.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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/messages.d.ts +1 -0
- package/dist/messages.js +2 -0
- package/dist/remote/app_user.remote.js +2 -3
- package/dist/remote/einladung.remote.d.ts +6 -1
- package/dist/remote/einladung.remote.js +4 -3
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.js +0 -1
- package/dist/server/repositories/UserRepo.d.ts +5 -2
- package/dist/server/repositories/UserRepo.js +5 -2
- package/dist/server/service/einladung.service.d.ts +3 -13
- package/dist/server/service/einladung.service.js +1 -11
- package/dist/ui/DeletionTab.svelte +2 -1
- package/dist/ui/LoginForm.svelte +9 -6
- package/dist/ui/RegisterForm.svelte +1 -1
- package/dist/ui/SettingsPage.svelte +1 -2
- package/dist/ui/SocialButton.svelte +3 -2
- package/dist/ui/TwoFactorAuthenticationCard.svelte +9 -5
- package/dist/util/fresh.js +1 -1
- package/package.json +9 -6
- package/dist/server/service/konto.service.d.ts +0 -7
- package/dist/server/service/konto.service.js +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @vonall/auth
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- The pass-through services are gone: `UserRepo.kontoLoeschen` replaces `KontoService.loeschen`; `EinladungRepo.listOpenBy`/`listAllOpen` replace `EinladungService.offene`/`alleOffenen`, and `EinladungService.zurueckziehen(null, id)` the admin's withdrawal; `AgentRepo` replaces `AgentService`. `@vonall/mcp`'s components use `@vonall/auth`'s `messageOf`.
|
|
8
|
+
|
|
9
|
+
## 0.3.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- The code review's fixes: `svelte-sonner`, `bits-ui`, `@lucide/svelte` and `mode-watcher` are peer dependencies (one copy per app, so toasts reach the Product's Toaster); the login page no longer echoes unknown `?error=` codes and clears the URL's reason on a new attempt; every path goes through the base path; the settings page stays where the Product mounted it; copying the backup codes reports a failure.
|
|
14
|
+
|
|
3
15
|
## 0.3.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ better-auth plugins and rate limit rule come from `@vonall/mcp` through `plugins
|
|
|
54
54
|
<!-- src/routes/auth/signup/+page.svelte --> <RegisterForm />
|
|
55
55
|
<!-- src/routes/auth/reset-password --> <ResetPasswordForm />
|
|
56
56
|
<!-- src/routes/einladung/[token] --> <EinladungPage {data} tagline={APP_TAGLINE} />
|
|
57
|
-
<!-- src/routes/home/settings --> <SettingsPage extraTabs={[
|
|
57
|
+
<!-- src/routes/home/settings --> <SettingsPage extraTabs={[{ id: "agents", label, hint, icon: Bot }]}>{#snippet extra(id)}…{/snippet}</SettingsPage>
|
|
58
58
|
<!-- src/routes/home/manage_user --> <AdminView currentUserId={data.currentUserId} />
|
|
59
59
|
```
|
|
60
60
|
|
package/dist/messages.d.ts
CHANGED
package/dist/messages.js
CHANGED
|
@@ -63,6 +63,7 @@ export const en = {
|
|
|
63
63
|
noNewAccountOpen: "Accounts can't be created at the moment. Please try again later.",
|
|
64
64
|
loginTooOld: "Your login is more than a day old. Please log in again for this action.",
|
|
65
65
|
confirmEmailFirst: "Confirm your email address first: we just sent you a new link.",
|
|
66
|
+
loginFailed: "Login failed.",
|
|
66
67
|
resetLinkNotSent: "The reset link could not be sent.",
|
|
67
68
|
resetLinkSent: "If an account with this email address exists, a link to reset the password has been sent.",
|
|
68
69
|
resetLinkNotRequested: "The reset link could not be requested.",
|
|
@@ -306,6 +307,7 @@ export const de = {
|
|
|
306
307
|
noNewAccountOpen: "Im Moment können keine Konten erstellt werden. Bitte versuch es später wieder.",
|
|
307
308
|
loginTooOld: "Deine Anmeldung ist älter als einen Tag. Melde dich für diese Aktion bitte neu an.",
|
|
308
309
|
confirmEmailFirst: "Bestätige zuerst deine E-Mail-Adresse: Wir haben dir gerade einen neuen Link geschickt.",
|
|
310
|
+
loginFailed: "Die Anmeldung hat nicht geklappt.",
|
|
309
311
|
resetLinkNotSent: "Der Link zum Zurücksetzen konnte nicht verschickt werden.",
|
|
310
312
|
resetLinkSent: "Wenn es ein Konto mit dieser E-Mail-Adresse gibt, ist ein Link zum Zurücksetzen des Passworts unterwegs.",
|
|
311
313
|
resetLinkNotRequested: "Der Link zum Zurücksetzen konnte nicht angefordert werden.",
|
|
@@ -5,7 +5,6 @@ import { m } from "../messages.js";
|
|
|
5
5
|
import { adminQuery, adminSchemaCommand, protectedCommand, protectedForm, protectedQuery, protectedSchemaCommand } from "../server/helpers.js";
|
|
6
6
|
import { authInstance } from "../server/registry.js";
|
|
7
7
|
import { UserRepo } from "../server/repositories/UserRepo.js";
|
|
8
|
-
import { KontoService } from "../server/service/konto.service.js";
|
|
9
8
|
import { emailSchema, nameSchema, passwordSchema } from "../types.js";
|
|
10
9
|
import { isSessionNotFresh, reauthPath } from "../util/fresh.js";
|
|
11
10
|
/** The Admin option: every account. */
|
|
@@ -80,12 +79,12 @@ export const deleteUser = adminSchemaCommand(z.object({ userId: z.string() }), a
|
|
|
80
79
|
if (userId === admin.id) {
|
|
81
80
|
throw error(400, { message: m().ownAccount, id: "own_account", timestamp: new Date().toISOString() });
|
|
82
81
|
}
|
|
83
|
-
await
|
|
82
|
+
await UserRepo.kontoLoeschen(userId);
|
|
84
83
|
await getAllUsers().refresh();
|
|
85
84
|
return { success: true };
|
|
86
85
|
});
|
|
87
86
|
/** Deletes the user's own account with all its data. */
|
|
88
87
|
export const deleteOwnAccount = protectedCommand(async (user) => {
|
|
89
|
-
await
|
|
88
|
+
await UserRepo.kontoLoeschen(user.id);
|
|
90
89
|
return { success: true };
|
|
91
90
|
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/** The user's open Einladungen, and whether the server can send them by email. */
|
|
2
2
|
export declare const getOffeneEinladungen: import("$app/server").RemoteQueryFunction<void, {
|
|
3
|
-
einladungen:
|
|
3
|
+
einladungen: {
|
|
4
|
+
id: string;
|
|
5
|
+
email: string | null;
|
|
6
|
+
expiresAt: Date;
|
|
7
|
+
createdAt: Date;
|
|
8
|
+
}[];
|
|
4
9
|
mail: boolean;
|
|
5
10
|
}, void>;
|
|
6
11
|
/** Creates an Einladung; the link is returned only here. With an email, it is also sent (if mail is set up). */
|
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { m } from "../messages.js";
|
|
4
4
|
import { adminQuery, adminSchemaCommand, protectedQuery, protectedSchemaCommand } from "../server/helpers.js";
|
|
5
5
|
import { registry } from "../server/registry.js";
|
|
6
|
+
import { EinladungRepo } from "../server/repositories/EinladungRepo.js";
|
|
6
7
|
import { EinladungService } from "../server/service/einladung.service.js";
|
|
7
8
|
import { sendEinladungEmail } from "../server/service/mail.js";
|
|
8
9
|
import { emailSchema } from "../types.js";
|
|
@@ -15,7 +16,7 @@ function unwrap(result) {
|
|
|
15
16
|
}
|
|
16
17
|
/** The user's open Einladungen, and whether the server can send them by email. */
|
|
17
18
|
export const getOffeneEinladungen = protectedQuery(async (user) => {
|
|
18
|
-
return { einladungen: await
|
|
19
|
+
return { einladungen: await EinladungRepo.listOpenBy(user.id, new Date()), mail: registry().mailer.enabled };
|
|
19
20
|
});
|
|
20
21
|
/** Creates an Einladung; the link is returned only here. With an email, it is also sent (if mail is set up). */
|
|
21
22
|
export const createEinladung = protectedSchemaCommand(z.object({ email: emailSchema.nullable() }), async ({ email }, user) => {
|
|
@@ -47,10 +48,10 @@ export const withdrawEinladung = protectedSchemaCommand(z.object({ einladungId:
|
|
|
47
48
|
});
|
|
48
49
|
/** The Admin option: every open Einladung, and withdrawing any of them. */
|
|
49
50
|
export const getAlleEinladungen = adminQuery(async () => {
|
|
50
|
-
return await
|
|
51
|
+
return await EinladungRepo.listAllOpen(new Date());
|
|
51
52
|
});
|
|
52
53
|
export const adminWithdrawEinladung = adminSchemaCommand(z.object({ einladungId: z.string() }), async ({ einladungId }) => {
|
|
53
|
-
unwrap(await EinladungService.
|
|
54
|
+
unwrap(await EinladungService.zurueckziehen(null, einladungId));
|
|
54
55
|
await getAlleEinladungen().refresh();
|
|
55
56
|
await getOffeneEinladungen().refresh();
|
|
56
57
|
});
|
package/dist/server/index.d.ts
CHANGED
|
@@ -5,5 +5,4 @@ export { authInstance, registry as authRegistry, type AuthLog, type Db } from ".
|
|
|
5
5
|
export { EinladungRepo } from "./repositories/EinladungRepo.js";
|
|
6
6
|
export { UserRepo } from "./repositories/UserRepo.js";
|
|
7
7
|
export { EINLADUNG_COOKIE, EINLADUNG_GUELTIG_TAGE, EinladungService, type EinladungError } from "./service/einladung.service.js";
|
|
8
|
-
export { KontoService } from "./service/konto.service.js";
|
|
9
8
|
export { sendEinladungEmail, sendPasswordResetEmail, sendVerifyEmail } from "./service/mail.js";
|
package/dist/server/index.js
CHANGED
|
@@ -5,5 +5,4 @@ export { authInstance, registry as authRegistry } from "./registry.js";
|
|
|
5
5
|
export { EinladungRepo } from "./repositories/EinladungRepo.js";
|
|
6
6
|
export { UserRepo } from "./repositories/UserRepo.js";
|
|
7
7
|
export { EINLADUNG_COOKIE, EINLADUNG_GUELTIG_TAGE, EinladungService } from "./service/einladung.service.js";
|
|
8
|
-
export { KontoService } from "./service/konto.service.js";
|
|
9
8
|
export { sendEinladungEmail, sendPasswordResetEmail, sendVerifyEmail } from "./service/mail.js";
|
|
@@ -14,6 +14,9 @@ export declare const UserRepo: {
|
|
|
14
14
|
providerId: string;
|
|
15
15
|
updatedAt: Date;
|
|
16
16
|
}[]>;
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Deletes the Konto: the user with everything that belongs to them (the foreign keys of every user-owned table
|
|
19
|
+
* cascade, so a Product's own tables reference `user.id` with `onDelete: "cascade"`).
|
|
20
|
+
*/
|
|
21
|
+
kontoLoeschen(userId: string): Promise<void>;
|
|
19
22
|
};
|
|
@@ -59,8 +59,11 @@ export const UserRepo = {
|
|
|
59
59
|
.from(schema.account)
|
|
60
60
|
.where(eq(schema.account.userId, userId));
|
|
61
61
|
},
|
|
62
|
-
/**
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Deletes the Konto: the user with everything that belongs to them (the foreign keys of every user-owned table
|
|
64
|
+
* cascade, so a Product's own tables reference `user.id` with `onDelete: "cascade"`).
|
|
65
|
+
*/
|
|
66
|
+
async kontoLoeschen(userId) {
|
|
64
67
|
const { db, schema } = registry();
|
|
65
68
|
await db.delete(schema.user).where(eq(schema.user.id, userId));
|
|
66
69
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Result } from "neverthrow";
|
|
2
|
-
import type { EinladungInfo,
|
|
2
|
+
import type { EinladungInfo, SignupMode, SignupState } from "../../types.js";
|
|
3
3
|
export declare const EINLADUNG_GUELTIG_TAGE = 14;
|
|
4
4
|
/** The cookie that carries an Einladung's token from its link through signup (email, Google or GitHub). */
|
|
5
5
|
export declare const EINLADUNG_COOKIE = "einladung";
|
|
@@ -33,16 +33,6 @@ export declare const EinladungService: {
|
|
|
33
33
|
}>;
|
|
34
34
|
/** Uses the Einladung for the new user: marks it as taken. */
|
|
35
35
|
annehmen(userId: string, token: string, now?: Date): Promise<Result<void, EinladungError>>;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
zurueckziehen(userId: string, einladungId: string): Promise<Result<void, EinladungError>>;
|
|
39
|
-
/** For the admin: every open Einladung, and withdrawing any of them. */
|
|
40
|
-
alleOffenen(now?: Date): Promise<{
|
|
41
|
-
id: string;
|
|
42
|
-
email: string | null;
|
|
43
|
-
inviterName: string;
|
|
44
|
-
expiresAt: Date;
|
|
45
|
-
createdAt: Date;
|
|
46
|
-
}[]>;
|
|
47
|
-
zurueckziehenAlsAdmin(einladungId: string): Promise<Result<void, EinladungError>>;
|
|
36
|
+
/** Withdraws an open Einladung of the user, or any open one when `userId` is null (the admin). */
|
|
37
|
+
zurueckziehen(userId: string | null, einladungId: string): Promise<Result<void, EinladungError>>;
|
|
48
38
|
};
|
|
@@ -59,18 +59,8 @@ export const EinladungService = {
|
|
|
59
59
|
return err(fehler.angenommen());
|
|
60
60
|
return ok(undefined);
|
|
61
61
|
},
|
|
62
|
-
|
|
63
|
-
return await EinladungRepo.listOpenBy(userId, now);
|
|
64
|
-
},
|
|
65
|
-
/** Withdraws an open Einladung of the user. */
|
|
62
|
+
/** Withdraws an open Einladung of the user, or any open one when `userId` is null (the admin). */
|
|
66
63
|
async zurueckziehen(userId, einladungId) {
|
|
67
64
|
return (await EinladungRepo.deleteOpen(einladungId, userId)) ? ok(undefined) : err(fehler.unbekannt());
|
|
68
65
|
},
|
|
69
|
-
/** For the admin: every open Einladung, and withdrawing any of them. */
|
|
70
|
-
async alleOffenen(now = new Date()) {
|
|
71
|
-
return await EinladungRepo.listAllOpen(now);
|
|
72
|
-
},
|
|
73
|
-
async zurueckziehenAlsAdmin(einladungId) {
|
|
74
|
-
return (await EinladungRepo.deleteOpen(einladungId, null)) ? ok(undefined) : err(fehler.unbekannt());
|
|
75
|
-
},
|
|
76
66
|
};
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { m } from "../messages.js";
|
|
9
9
|
import { deleteOwnAccount } from "../remote/app_user.remote.js";
|
|
10
10
|
import { authUi } from "./context.js";
|
|
11
|
+
import { href } from "./href.js";
|
|
11
12
|
import { messageOf } from "../util/messageOf.js";
|
|
12
13
|
|
|
13
14
|
/** Deleting the own account; `agents` adds the sentence about connected AI assistants (the MCP endpoint). */
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
if (res.success) {
|
|
28
29
|
toast.success(m().accountDeleted);
|
|
29
30
|
await authClient.signOut().catch(() => undefined);
|
|
30
|
-
window.location.href = "/";
|
|
31
|
+
window.location.href = href("/");
|
|
31
32
|
} else {
|
|
32
33
|
toast.error(m().accountNotDeleted);
|
|
33
34
|
}
|
package/dist/ui/LoginForm.svelte
CHANGED
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
const providers = $derived(page.data.providers as { github?: boolean; google?: boolean } | undefined);
|
|
38
38
|
const mail = $derived(page.data.mail as boolean);
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
// The reason the URL brought along (a refused social signup, a stale login); a fresh attempt replaces it
|
|
41
|
+
let urlError = $derived(page.url.searchParams.get("error"));
|
|
41
42
|
// A new account through GitHub or Google was refused: why depends on the signup mode
|
|
42
43
|
const noNewAccount = $derived(signupMode === "open" ? m().noNewAccountOpen : m().noNewAccountInvite);
|
|
43
44
|
const URL_ERRORS = $derived<Record<string, string>>({
|
|
@@ -47,7 +48,8 @@
|
|
|
47
48
|
session_not_fresh: m().loginTooOld,
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
// Only known reasons are shown; an unknown code is not echoed (a link could plant any text here)
|
|
52
|
+
const displayError = $derived(urlError ? (URL_ERRORS[urlError.toLowerCase()] ?? m().loginFailed) : errorMessage);
|
|
51
53
|
|
|
52
54
|
async function requestPasswordReset(e: SubmitEvent) {
|
|
53
55
|
e.preventDefault();
|
|
@@ -57,7 +59,7 @@
|
|
|
57
59
|
}
|
|
58
60
|
sendingResetLink = true;
|
|
59
61
|
try {
|
|
60
|
-
const res = await authClient.requestPasswordReset({ email: forgotPasswordEmail, redirectTo: `${window.location.origin}/auth/reset-password` });
|
|
62
|
+
const res = await authClient.requestPasswordReset({ email: forgotPasswordEmail, redirectTo: `${window.location.origin}${href("/auth/reset-password")}` });
|
|
61
63
|
if (res.error) {
|
|
62
64
|
toast.error(res.error.message || m().resetLinkNotSent);
|
|
63
65
|
} else {
|
|
@@ -84,7 +86,7 @@
|
|
|
84
86
|
if (oauthRequest) {
|
|
85
87
|
// Fallback: with a session, the authorize endpoint continues the flow in the browser
|
|
86
88
|
const query = [...page.url.searchParams].filter(([key]) => key !== "sig" && key !== "exp");
|
|
87
|
-
window.location.href =
|
|
89
|
+
window.location.href = `${href("/api/auth/oauth2/authorize")}?${query.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&")}`;
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
92
|
// A new login: queries cached before it (one that sent here to log in again resolved empty) load again
|
|
@@ -99,6 +101,7 @@
|
|
|
99
101
|
onRequest: () => {
|
|
100
102
|
loading = true;
|
|
101
103
|
errorMessage = "";
|
|
104
|
+
urlError = null;
|
|
102
105
|
},
|
|
103
106
|
onSuccess: async (ctx) => {
|
|
104
107
|
loading = false;
|
|
@@ -169,8 +172,8 @@
|
|
|
169
172
|
<div class="grid gap-6">
|
|
170
173
|
{#if providers?.github || providers?.google}
|
|
171
174
|
<div class="flex flex-col gap-4">
|
|
172
|
-
{#if providers.github}<SocialButton provider="github" callbackURL={redirectTo ?? "/home"} />{/if}
|
|
173
|
-
{#if providers.google}<SocialButton provider="google" callbackURL={redirectTo ?? "/home"} />{/if}
|
|
175
|
+
{#if providers.github}<SocialButton provider="github" callbackURL={redirectTo ?? href("/home")} />{/if}
|
|
176
|
+
{#if providers.google}<SocialButton provider="google" callbackURL={redirectTo ?? href("/home")} />{/if}
|
|
174
177
|
</div>
|
|
175
178
|
<div class="after:border-border relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t">
|
|
176
179
|
<span class="bg-card text-muted-foreground relative z-10 px-2">{m().orWithEmail}</span>
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
}
|
|
40
40
|
const name = email.split("@")[0]; // the server turns it into a readable name
|
|
41
41
|
await authClient.signUp.email(
|
|
42
|
-
{ email, password, name, callbackURL: "/home" },
|
|
42
|
+
{ email, password, name, callbackURL: href("/home") },
|
|
43
43
|
{
|
|
44
44
|
onRequest: () => {
|
|
45
45
|
loading = true;
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import type { AppUserClient } from "../types.js";
|
|
9
9
|
import { authUi } from "./context.js";
|
|
10
10
|
import DeletionTab from "./DeletionTab.svelte";
|
|
11
|
-
import { href } from "./href.js";
|
|
12
11
|
import InvitationsTab from "./InvitationsTab.svelte";
|
|
13
12
|
import LinksTab from "./LinksTab.svelte";
|
|
14
13
|
import MobileSettingsMenu from "./MobileSettingsMenu.svelte";
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
const url = new URL(page.url.href);
|
|
49
48
|
if (tabName) url.searchParams.set("tab", tabName);
|
|
50
49
|
else url.searchParams.delete("tab");
|
|
51
|
-
goto(`${
|
|
50
|
+
goto(`${page.url.pathname}${url.search}`); // wherever the Product mounted this page
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
const memberSince = $derived(user.createdAt ? new Date(user.createdAt).toLocaleDateString(locale, { year: "numeric", month: "long" }) : "");
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
import { Button } from "../components/ui/button/index.js";
|
|
3
3
|
import { m } from "../messages.js";
|
|
4
4
|
import { authUi } from "./context.js";
|
|
5
|
+
import { href } from "./href.js";
|
|
5
6
|
import IconGithub from "./IconGithub.svelte";
|
|
6
7
|
import IconGoogle from "./IconGoogle.svelte";
|
|
7
8
|
|
|
8
9
|
/** "Continue with GitHub/Google": starts the social sign-in with the Product's client. */
|
|
9
|
-
let { provider, callbackURL = "/home" }: { provider: "github" | "google"; callbackURL?: string } = $props();
|
|
10
|
+
let { provider, callbackURL = href("/home") }: { provider: "github" | "google"; callbackURL?: string } = $props();
|
|
10
11
|
const { authClient } = authUi();
|
|
11
12
|
const names = { github: "GitHub", google: "Google" };
|
|
12
13
|
|
|
13
14
|
async function login() {
|
|
14
|
-
await authClient.signIn.social({ provider, callbackURL, errorCallbackURL: "/auth/login" });
|
|
15
|
+
await authClient.signIn.social({ provider, callbackURL, errorCallbackURL: href("/auth/login") });
|
|
15
16
|
}
|
|
16
17
|
</script>
|
|
17
18
|
|
|
@@ -98,11 +98,15 @@
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
function handleCopyBackupCodes() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
async function handleCopyBackupCodes() {
|
|
102
|
+
try {
|
|
103
|
+
await navigator.clipboard.writeText(backupCodes.join("\n"));
|
|
104
|
+
isCopied = true;
|
|
105
|
+
toast.success(m().backupCodesCopied);
|
|
106
|
+
setTimeout(() => (isCopied = false), 2000);
|
|
107
|
+
} catch {
|
|
108
|
+
toast.error(m().copyLinkFailed);
|
|
109
|
+
}
|
|
106
110
|
}
|
|
107
111
|
</script>
|
|
108
112
|
|
package/dist/util/fresh.js
CHANGED
|
@@ -12,7 +12,7 @@ export function isSessionNotFresh(e) {
|
|
|
12
12
|
}
|
|
13
13
|
/** The login page that signs out a stale session and then returns to `redirectTo`. */
|
|
14
14
|
export function reauthPath(redirectTo) {
|
|
15
|
-
return `/auth/login?error=${SESSION_NOT_FRESH.toLowerCase()}&redirectTo=${encodeURIComponent(redirectTo)}`;
|
|
15
|
+
return `/auth/login?error=${SESSION_NOT_FRESH.toLowerCase()}&redirectTo=${encodeURIComponent(redirectTo)}`; // the Product's loads prefix the base path
|
|
16
16
|
}
|
|
17
17
|
/** better-auth's own check: a `freshAge` of 0 turns it off. */
|
|
18
18
|
export function isStale(createdAt, freshAgeSeconds, now = new Date()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vonall/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Accounts for a Web App Factory Product: better-auth with the hooks, the protected helpers, Einladungen, Konto, the auth pages and the settings; Admin as an option",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,7 +58,10 @@
|
|
|
58
58
|
"neverthrow": "^8.2.0",
|
|
59
59
|
"pg": "^8.23.1",
|
|
60
60
|
"svelte": "^5.57.2",
|
|
61
|
-
"zod": "^4.6.7"
|
|
61
|
+
"zod": "^4.6.7",
|
|
62
|
+
"svelte-sonner": "^1.2.1",
|
|
63
|
+
"bits-ui": "^2.19.5",
|
|
64
|
+
"@lucide/svelte": "^1.22.0"
|
|
62
65
|
},
|
|
63
66
|
"devDependencies": {
|
|
64
67
|
"@better-auth/mcp": "^1.7.12",
|
|
@@ -78,7 +81,10 @@
|
|
|
78
81
|
"typescript": "^6.0.3",
|
|
79
82
|
"vite": "8.3.4",
|
|
80
83
|
"vitest": "^5.0.5",
|
|
81
|
-
"zod": "^4.6.7"
|
|
84
|
+
"zod": "^4.6.7",
|
|
85
|
+
"svelte-sonner": "^1.2.1",
|
|
86
|
+
"bits-ui": "^2.19.5",
|
|
87
|
+
"@lucide/svelte": "^1.22.0"
|
|
82
88
|
},
|
|
83
89
|
"imports": {
|
|
84
90
|
"#lib": "./src/lib/index.js",
|
|
@@ -91,11 +97,8 @@
|
|
|
91
97
|
"access": "public"
|
|
92
98
|
},
|
|
93
99
|
"dependencies": {
|
|
94
|
-
"@lucide/svelte": "1.22.0",
|
|
95
100
|
"better-auth": "^1.7.12",
|
|
96
|
-
"bits-ui": "^2.20.2",
|
|
97
101
|
"clsx": "^2.1.1",
|
|
98
|
-
"svelte-sonner": "^1.2.1",
|
|
99
102
|
"tailwind-merge": "^3.7.0",
|
|
100
103
|
"tailwind-variants": "^3.3.1",
|
|
101
104
|
"uqr": "^0.1.3",
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare const KontoService: {
|
|
2
|
-
/**
|
|
3
|
-
* Deletes the account with everything that belongs to it: the foreign keys of every user-owned table cascade, so a
|
|
4
|
-
* Product's own tables reference `user.id` with `onDelete: "cascade"`.
|
|
5
|
-
*/
|
|
6
|
-
loeschen(userId: string): Promise<void>;
|
|
7
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/** The user's account as a whole. */
|
|
2
|
-
import { UserRepo } from "../repositories/UserRepo.js";
|
|
3
|
-
export const KontoService = {
|
|
4
|
-
/**
|
|
5
|
-
* Deletes the account with everything that belongs to it: the foreign keys of every user-owned table cascade, so a
|
|
6
|
-
* Product's own tables reference `user.id` with `onDelete: "cascade"`.
|
|
7
|
-
*/
|
|
8
|
-
async loeschen(userId) {
|
|
9
|
-
await UserRepo.deleteUser(userId);
|
|
10
|
-
},
|
|
11
|
-
};
|