@protobase/server 0.45.14 → 0.45.15

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,5 +1,6 @@
1
1
  import "./account-exists-email.js";
2
2
  import "./invitation-email.js";
3
+ import "./no-account-email.js";
3
4
  import "./reset-password-email.js";
4
5
  import "./sign-in-code-email.js";
5
6
  import "./sign-up-code-email.js";
@@ -1,8 +1,9 @@
1
1
  import { accountExistsEmail } from "./account-exists-email.js";
2
2
  import { invitationEmail } from "./invitation-email.js";
3
+ import { noAccountEmail } from "./no-account-email.js";
3
4
  import { resetPasswordEmail } from "./reset-password-email.js";
4
5
  import { signInCodeEmail } from "./sign-in-code-email.js";
5
6
  import { signUpCodeEmail } from "./sign-up-code-email.js";
6
7
  import { staffSignInEmail } from "./staff-sign-in-email.js";
7
8
  import { twoFactorCodeEmail } from "./two-factor-code-email.js";
8
- export { accountExistsEmail, invitationEmail, resetPasswordEmail, signInCodeEmail, signUpCodeEmail, staffSignInEmail, twoFactorCodeEmail };
9
+ export { accountExistsEmail, invitationEmail, noAccountEmail, resetPasswordEmail, signInCodeEmail, signUpCodeEmail, staffSignInEmail, twoFactorCodeEmail };
@@ -0,0 +1 @@
1
+ import "../../index.js";
@@ -0,0 +1,32 @@
1
+ import { defineEmail } from "../../mail/define-email.js";
2
+ import { EmailButton, EmailLayout, EmailNote } from "../../mail/email-layout.js";
3
+ import { signInPath } from "@protobase/schema";
4
+ import { Text } from "react-email";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/better-auth/auth-mail/no-account-email.tsx
7
+ const NoAccountEmail = ({ app }) => /* @__PURE__ */ jsxs(EmailLayout, {
8
+ app,
9
+ preview: `No ${app.name} account uses this address`,
10
+ heading: "No account for this address",
11
+ children: [
12
+ /* @__PURE__ */ jsxs(Text, { children: [
13
+ "Someone asked for a code to sign in to ",
14
+ app.name,
15
+ " with this address. No account uses it, so no code was sent."
16
+ ] }),
17
+ /* @__PURE__ */ jsx(Text, { children: "If you have an account, sign in again with the address you signed up with." }),
18
+ /* @__PURE__ */ jsxs(EmailButton, {
19
+ href: new URL(signInPath(), app.url).href,
20
+ children: ["Sign in to ", app.name]
21
+ }),
22
+ /* @__PURE__ */ jsx(EmailNote, { children: "If this was not you, ignore this email: nothing was changed." })
23
+ ]
24
+ });
25
+ /** The email to an address that asked for a sign-in code while no account uses it: no code, a hint to try another address. */
26
+ const noAccountEmail = defineEmail({
27
+ name: "no-account",
28
+ subject: ({ app }) => `No ${app.name} account uses this address`,
29
+ component: NoAccountEmail
30
+ });
31
+ //#endregion
32
+ export { noAccountEmail };
@@ -3118,6 +3118,14 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
3118
3118
  INVALID_OTP: import("better-auth").RawError<"INVALID_OTP">;
3119
3119
  TOO_MANY_ATTEMPTS: import("better-auth").RawError<"TOO_MANY_ATTEMPTS">;
3120
3120
  };
3121
+ } | {
3122
+ id: "protobase-no-account-mail";
3123
+ hooks: {
3124
+ after: {
3125
+ matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
3126
+ handler: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>;
3127
+ }[];
3128
+ };
3121
3129
  } | {
3122
3130
  id: "protobase-sign-up";
3123
3131
  endpoints: {
@@ -3744,7 +3752,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
3744
3752
  userId: string;
3745
3753
  expiresAt: Date;
3746
3754
  token: string;
3747
- ipAddress?: string | null | undefined;
3755
+ ipAddress? /** The app keeps each user's metadata, in the column `users.metadata` names. */ : string | null | undefined;
3748
3756
  userAgent?: string | null | undefined;
3749
3757
  };
3750
3758
  user: Record<string, any> & {
@@ -29,6 +29,7 @@ import { platformSignInFor, platformSignInProvider, readPlatformSignIn, resolveP
29
29
  import { appSignInPolicy } from "./app-sign-in-policy.js";
30
30
  import { assertNoEndpointKeyClashes } from "./endpoint-key-clashes.js";
31
31
  import { emailInDomains, resolveSamlProviders, samlDisabledPaths, samlGuardPlugin, samlPlugin } from "./saml-sign-in.js";
32
+ import { noAccountMailPlugin } from "./no-account-mail.js";
32
33
  import { emailCodeOptions, twoFactorCodeOptions, unusedEmailCodePaths } from "./sign-in-mail.js";
33
34
  import { signUpPaths, signUpPlugin } from "./sign-up/sign-up-plugin.js";
34
35
  import { confirmedOnCreate, confirmedOnUpdate, emailConfirmedField } from "./email-confirmed.js";
@@ -162,7 +163,7 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
162
163
  formerDomain: hosts[0],
163
164
  origins: appOrigins(options.baseURL, origins)
164
165
  }),
165
- ...mail ? [emailOTP(emailCodeOptions(mail))] : [],
166
+ ...mail ? [emailOTP(emailCodeOptions(mail)), noAccountMailPlugin(mail)] : [],
166
167
  ...mail && signUpRole ? [signUpPlugin({
167
168
  role: signUpRole,
168
169
  mail,
@@ -0,0 +1,24 @@
1
+ import { sendAuthEmail } from "./auth-mail/send-auth-email.js";
2
+ import { APIError, createAuthMiddleware } from "better-auth/api";
3
+ //#region src/better-auth/no-account-mail.ts
4
+ /**
5
+ * Mails an address that asked for a sign-in code while no account uses it, so its owner knows to try another address.
6
+ * The email OTP plugin answers such a request as it answers one for an account, and mails nothing; this hook sends the
7
+ * no-account email after it, so the answer still tells nobody which addresses have an account.
8
+ */
9
+ const noAccountMailPlugin = (mail) => ({
10
+ id: "protobase-no-account-mail",
11
+ hooks: { after: [{
12
+ matcher: (ctx) => ctx.path === "/email-otp/send-verification-otp",
13
+ handler: createAuthMiddleware(async (ctx) => {
14
+ if (ctx.context.returned instanceof APIError) return;
15
+ const { email, type } = ctx.body;
16
+ if (type !== "sign-in") return;
17
+ const address = email.toLowerCase();
18
+ if (await ctx.context.internalAdapter.findUserByEmail(address)) return;
19
+ await ctx.context.runInBackgroundOrAwait(sendAuthEmail(mail, "noAccountEmail", address, {}, ctx.context.baseURL));
20
+ })
21
+ }] }
22
+ });
23
+ //#endregion
24
+ export { noAccountMailPlugin };
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.45.14";
2
+ var version = "0.45.15";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.45.14",
3
+ "version": "0.45.15",
4
4
  "description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "@better-auth/passkey": "^1.7.12",
37
37
  "@better-auth/sso": "^1.7.12",
38
38
  "@modelcontextprotocol/server": "^2.3.1",
39
- "@protobase/layout": "0.45.14",
40
- "@protobase/query": "0.45.14",
41
- "@protobase/schema": "0.45.14",
39
+ "@protobase/layout": "0.45.15",
40
+ "@protobase/query": "0.45.15",
41
+ "@protobase/schema": "0.45.15",
42
42
  "@react-email/render": "^2.1.0",
43
43
  "@scalar/hono-api-reference": "^0.12.10",
44
44
  "@sentry/core": "^11.7.0",