@vonall/auth 0.5.0 → 0.6.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.
@@ -1,40 +1,38 @@
1
- /** The three mails of accounts, through the Product's mailer (`@vonall/mail`). */
1
+ /** The three mails of accounts, through the Product's mailer (`@vonall/mail`), in the app's name and locale. */
2
2
  import { renderMail } from "@vonall/mail";
3
3
  import { m } from "../../messages.js";
4
- import { registry } from "../registry.js";
5
4
  import InvitationEmail from "../../templates/InvitationEmail.svelte";
6
5
  import ResetPasswordEmail from "../../templates/ResetPasswordEmail.svelte";
7
6
  import VerifyEmailEmail from "../../templates/VerifyEmailEmail.svelte";
8
- function footer() {
9
- const { appName, origin } = registry();
10
- return { appName, appLink: origin };
11
- }
12
- const footerText = (appName) => `\n---\n${appName}\n`;
13
- export async function sendPasswordResetEmail(user, url) {
14
- const { mailer, appName } = registry();
15
- await mailer.send({
16
- to: user.email,
17
- subject: m().resetSubject(appName),
18
- text: m().resetText(user.name, appName, url) + footerText(appName),
19
- html: renderMail(ResetPasswordEmail, { recipientName: user.name, link: url, ...footer() }),
20
- });
21
- }
22
- export async function sendVerifyEmail(user, url) {
23
- const { mailer, appName } = registry();
24
- await mailer.send({
25
- to: user.email,
26
- subject: m().verifySubject(appName),
27
- text: m().verifyText(user.name, appName, url) + footerText(appName),
28
- html: renderMail(VerifyEmailEmail, { recipientName: user.name, link: url, ...footer() }),
29
- });
30
- }
31
- export async function sendEinladungEmail(inviterName, to, einladung, locale) {
32
- const { mailer, appName } = registry();
33
- const validUntil = new Intl.DateTimeFormat(locale, { dateStyle: "long" }).format(einladung.expiresAt);
34
- await mailer.send({
35
- to,
36
- subject: m().einladungSubject(inviterName, appName),
37
- text: m().einladungText(inviterName, appName, einladung.link, validUntil) + footerText(appName),
38
- html: renderMail(InvitationEmail, { inviterName, link: einladung.link, validUntil, ...footer() }),
39
- });
7
+ export function authMails(ctx) {
8
+ const { mailer, appName, origin, locale } = ctx;
9
+ const footer = { appName, appLink: origin };
10
+ const footerText = `\n---\n${appName}\n`;
11
+ return {
12
+ async passwordReset(user, url) {
13
+ await mailer.send({
14
+ to: user.email,
15
+ subject: m().resetSubject(appName),
16
+ text: m().resetText(user.name, appName, url) + footerText,
17
+ html: renderMail(ResetPasswordEmail, { recipientName: user.name, link: url, ...footer }),
18
+ });
19
+ },
20
+ async verify(user, url) {
21
+ await mailer.send({
22
+ to: user.email,
23
+ subject: m().verifySubject(appName),
24
+ text: m().verifyText(user.name, appName, url) + footerText,
25
+ html: renderMail(VerifyEmailEmail, { recipientName: user.name, link: url, ...footer }),
26
+ });
27
+ },
28
+ async einladung(inviterName, to, einladung) {
29
+ const validUntil = new Intl.DateTimeFormat(locale, { dateStyle: "long" }).format(einladung.expiresAt);
30
+ await mailer.send({
31
+ to,
32
+ subject: m().einladungSubject(inviterName, appName),
33
+ text: m().einladungText(inviterName, appName, einladung.link, validUntil) + footerText,
34
+ html: renderMail(InvitationEmail, { inviterName, link: einladung.link, validUntil, ...footer }),
35
+ });
36
+ },
37
+ };
40
38
  }
@@ -1,15 +1,13 @@
1
+ import { type AuthSchema } from "../schema/index.js";
2
+ import type { AuthContext, Db } from "../server/context.js";
1
3
  import { type CreateAuthOptions } from "../server/create.js";
2
- import type { Db } from "../server/registry.js";
3
4
  /** Creates a user directly (the first one becomes admin, as in the app) and returns its id. */
4
- export declare function createUser(email?: string): Promise<string>;
5
+ export declare function createUser(ctx: AuthContext, email?: string): Promise<string>;
5
6
  /** The wiring with test values: every option on, mail off, unless overridden; as a Product's `src/lib/auth.ts` does it. */
6
- export declare function testAuth(db: Db, overrides?: Partial<CreateAuthOptions>): {
7
- handle: import("@sveltejs/kit/hooks").Handle;
7
+ export declare function testAuth(db: Db, overrides?: Partial<CreateAuthOptions<AuthSchema<true, true>>>): {
8
+ ctx: AuthContext<AuthSchema<boolean, boolean>>;
9
+ sessionHandle: import("@sveltejs/kit/hooks").Handle;
8
10
  apiHandler: import("@sveltejs/kit").RequestHandler;
9
- providers: {
10
- github: boolean;
11
- google: boolean;
12
- };
13
11
  auth: import("better-auth").Auth<{
14
12
  plugins: [{
15
13
  id: "two-factor";
@@ -7,30 +7,27 @@ import { sveltekitCookies } from "better-auth/svelte-kit";
7
7
  import { createMailer } from "@vonall/mail";
8
8
  import { ac, roles } from "../permissions.js";
9
9
  import { authSchema } from "../schema/index.js";
10
- import { authOptions, registerAuth } from "../server/create.js";
11
- import { UserRepo } from "../server/repositories/UserRepo.js";
10
+ import { createAuth } from "../server/create.js";
11
+ import { userRepo } from "../server/repositories/UserRepo.js";
12
12
  /** Creates a user directly (the first one becomes admin, as in the app) and returns its id. */
13
- export async function createUser(email = "user@example.com") {
13
+ export async function createUser(ctx, email = "user@example.com") {
14
14
  const id = crypto.randomUUID();
15
- await UserRepo.insertUser({ id, email, name: "", emailVerified: true, createdAt: new Date(), updatedAt: new Date() });
15
+ await userRepo(ctx).insertUser({ id, email, name: "", emailVerified: true, createdAt: new Date(), updatedAt: new Date() });
16
16
  return id;
17
17
  }
18
18
  /** The wiring with test values: every option on, mail off, unless overridden; as a Product's `src/lib/auth.ts` does it. */
19
19
  export function testAuth(db, overrides = {}) {
20
- const auth = betterAuth({
21
- ...authOptions({
22
- db,
23
- schema: authSchema({ admin: true, mcp: true }),
24
- secret: "test-secret-for-the-db-tests-only",
25
- origin: "http://localhost:5173",
26
- appName: "Test",
27
- locale: "en-GB",
28
- signupMode: "invite",
29
- mailer: createMailer({ smtp: null }),
30
- admin: true,
31
- ...overrides,
32
- }),
33
- plugins: [twoFactor(), adminPlugin({ ac, roles }), sveltekitCookies(getRequestEvent)],
20
+ const wiring = createAuth({
21
+ db,
22
+ schema: authSchema({ admin: true, mcp: true }),
23
+ secret: "test-secret-for-the-db-tests-only",
24
+ origin: "http://localhost:5173",
25
+ appName: "Test",
26
+ locale: "en-GB",
27
+ signupMode: "invite",
28
+ mailer: createMailer({ smtp: null }),
29
+ ...overrides,
34
30
  });
35
- return { auth, ...registerAuth(auth) };
31
+ const auth = betterAuth({ ...wiring.options, plugins: [twoFactor(), adminPlugin({ ac, roles }), sveltekitCookies(getRequestEvent)] });
32
+ return { auth, ...wiring.register(auth) };
36
33
  }
@@ -1,4 +1,4 @@
1
- import type { SignupMode } from "../types.js";
1
+ import type { AuthUiData } from "../server/loads.js";
2
2
  type Outcome<T = unknown> = Promise<{
3
3
  data?: T | null;
4
4
  error?: {
@@ -80,14 +80,13 @@ export type AuthClientLike = {
80
80
  providerId?: string;
81
81
  }): Outcome;
82
82
  };
83
- export type AuthUi = {
83
+ export type AuthUi = AuthUiData & {
84
84
  authClient: AuthClientLike;
85
- appName: string;
86
- /** For dates, e.g. "de-CH". */
87
- locale: string;
88
- signupMode: SignupMode;
89
85
  };
90
86
  /** In the Product's root layout. */
91
- export declare function setAuthUi(ui: AuthUi): AuthUi;
87
+ export declare function setAuthUi({ authClient }: {
88
+ authClient: AuthClientLike;
89
+ }): void;
90
+ /** In a component: the client, and the app's facts from the page data. */
92
91
  export declare function authUi(): AuthUi;
93
92
  export {};
@@ -1,17 +1,23 @@
1
1
  /**
2
- * What the auth components need from the Product, set once in its root layout (`setAuthUi({ … })` during component
3
- * init): the better-auth client (the Product builds it, see `src/lib/auth-client.ts`), the app's name, its locale and
4
- * signup mode.
2
+ * What the auth components need: the better-auth client, set once in the Product's root layout (`setAuthUi({ authClient })`
3
+ * during component init; the Product builds the client, see `src/lib/auth-client.ts`), and the app's name, locale
4
+ * and signup mode, which this package's loads put into the page data (`authUi` in `authLayoutLoad`, `homeLayoutLoad`,
5
+ * `einladungLoad`).
5
6
  */
6
7
  import { getContext, setContext } from "svelte";
8
+ import { page } from "$app/state";
7
9
  const KEY = Symbol("vonall-auth-ui");
8
10
  /** In the Product's root layout. */
9
- export function setAuthUi(ui) {
10
- return setContext(KEY, ui);
11
+ export function setAuthUi({ authClient }) {
12
+ setContext(KEY, authClient);
11
13
  }
14
+ /** In a component: the client, and the app's facts from the page data. */
12
15
  export function authUi() {
13
- const ui = getContext(KEY);
14
- if (!ui)
15
- throw new Error("@vonall/auth: setAuthUi({ authClient, appName, locale, signupMode }) has not run in the root layout");
16
- return ui;
16
+ const authClient = getContext(KEY);
17
+ if (!authClient)
18
+ throw new Error("@vonall/auth: setAuthUi({ authClient }) has not run in the root layout");
19
+ const data = page.data.authUi;
20
+ if (!data)
21
+ throw new Error("@vonall/auth: this page's data has no `authUi`; its load or its layout's must be one of this package's (authLayoutLoad, homeLayoutLoad, einladungLoad)");
22
+ return { authClient, ...data };
17
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonall/auth",
3
- "version": "0.5.0",
3
+ "version": "0.6.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": {
@@ -102,8 +102,8 @@
102
102
  "tailwind-merge": "^3.7.0",
103
103
  "tailwind-variants": "^3.3.1",
104
104
  "uqr": "^0.1.3",
105
- "@vonall/messages": "^0.1.0",
106
- "@vonall/mail": "^0.2.0"
105
+ "@vonall/mail": "^0.2.0",
106
+ "@vonall/messages": "^0.1.0"
107
107
  },
108
108
  "scripts": {
109
109
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
@@ -1,22 +0,0 @@
1
- let current = null;
2
- export function setRegistry(registry) {
3
- current = registry;
4
- }
5
- export function registry() {
6
- if (!current)
7
- throw new Error("@vonall/auth: authOptions() has not run; import the app's auth wiring (src/lib/auth.ts) first");
8
- return current;
9
- }
10
- /** The Product's better-auth instance. */
11
- export function authInstance() {
12
- const auth = registry().auth;
13
- if (!auth)
14
- throw new Error("@vonall/auth: registerAuth(auth) has not run; the app's auth wiring (src/lib/auth.ts) calls it after betterAuth()");
15
- return auth;
16
- }
17
- export const consoleLog = {
18
- debug: () => { },
19
- info: (message, context) => console.info(message, context ?? ""),
20
- warn: (message, context) => console.warn(message, context ?? ""),
21
- error: (message, context, error) => console.error(message, context ?? "", error ?? ""),
22
- };