fix: session inference breaking on some plugins

This commit is contained in:
Bereket Engida
2024-10-01 08:14:59 +03:00
parent ee796b21ee
commit 6f0918dadf
10 changed files with 108 additions and 117 deletions

13
dev/bun/_auth.ts Normal file
View File

@@ -0,0 +1,13 @@
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { twoFactor } from "better-auth/plugins";
export const auth = betterAuth({
database: prismaAdapter(
{},
{
provider: "mysql",
},
),
plugins: [twoFactor()],
});

View File

@@ -1,13 +0,0 @@
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { twoFactor } from "better-auth/plugins";
export const auth = betterAuth({
database: prismaAdapter(
{},
{
provider: "mysql",
},
),
plugins: [twoFactor()],
});

View File

@@ -1,4 +1,4 @@
import { auth } from "./auth";
import { auth } from "./_auth";
Bun.serve({
fetch(request, server) {

View File

@@ -60,7 +60,7 @@
"@types/react": "^18.3.3",
"better-sqlite3": "^11.3.0",
"drizzle-orm": "^0.33.0",
"happy-dom": "^15.7.3",
"happy-dom": "^15.7.4",
"hono": "^4.5.4",
"listhen": "^1.7.2",
"mongodb": "^6.9.0",

View File

@@ -1,40 +1,18 @@
import type { BetterFetch } from "@better-fetch/fetch";
import { atom } from "nanostores";
import type { Auth as BetterAuth } from "../auth";
import type { Prettify, UnionToIntersection } from "../types/helper";
import type { InferSession, InferUser } from "../types/models";
import type { BetterAuthClientPlugin, ClientOptions } from "./types";
import type { Prettify } from "../types/helper";
import type {
ClientOptions,
InferSessionFromClient,
InferUserFromClient,
} from "./types";
import { useAuthQuery } from "./query";
import type { BetterAuthPlugin } from "../plugins";
export function getSessionAtom<Option extends ClientOptions>(
$fetch: BetterFetch,
) {
type Plugins = Option["plugins"] extends Array<BetterAuthClientPlugin>
? Array<
Option["plugins"][number] extends infer T
? T extends BetterAuthClientPlugin
? T["$InferServerPlugin"] extends infer U
? U extends BetterAuthPlugin
? U
: never
: never
: never
: never
>
: never;
type Auth = {
handler: any;
api: any;
options: {
database: any;
plugins: Plugins;
};
};
type UserWithAdditionalFields = InferUser<Auth["options"]>;
type SessionWithAdditionalFields = InferSession<Auth["options"]>;
type UserWithAdditionalFields = InferUserFromClient<Option>;
type SessionWithAdditionalFields = InferSessionFromClient<Option>;
const $signal = atom<boolean>(false);
const session = useAuthQuery<{
user: Prettify<UserWithAdditionalFields>;
@@ -47,8 +25,8 @@ export function getSessionAtom<Option extends ClientOptions>(
_sessionSignal: $signal,
$Infer: {} as {
Session: {
session: Prettify<SessionWithAdditionalFields>;
user: Prettify<UserWithAdditionalFields>;
session: SessionWithAdditionalFields;
user: UserWithAdditionalFields;
};
},
};

View File

@@ -5,10 +5,15 @@ import type {
} from "@better-fetch/fetch";
import type { BetterAuthPlugin } from "../types/plugins";
import type { Atom } from "nanostores";
import type { LiteralString, UnionToIntersection } from "../types/helper";
import type {
LiteralString,
StripEmptyObjects,
UnionToIntersection,
} from "../types/helper";
import type { Auth } from "../auth";
import type { InferRoutes } from "./path-to-object";
import type { InferSession, InferUser } from "../types";
import type { InferSession, InferUser, Session, User } from "../types";
import type { FieldAttribute, InferFieldOutput } from "../db";
export type AtomListener = {
matcher: (path: string) => boolean;
@@ -93,19 +98,43 @@ export type InferPluginsFromClient<O extends ClientOptions> =
? Array<O["plugins"][number]["$InferServerPlugin"]>
: undefined;
type InferAuthFromClient<O extends ClientOptions> = {
handler: any;
api: any;
options: {
database: any;
plugins: InferPluginsFromClient<O>;
export type InferSessionFromClient<O extends ClientOptions> = StripEmptyObjects<
Session & UnionToIntersection<InferAdditionalFromClient<O, "session">>
>;
export type InferUserFromClient<O extends ClientOptions> = StripEmptyObjects<
User & UnionToIntersection<InferAdditionalFromClient<O, "user">>
>;
export type InferAdditionalFromClient<
Options extends ClientOptions,
Key extends string,
> = Options["plugins"] extends Array<infer T>
? T extends BetterAuthClientPlugin
? T["$InferServerPlugin"] extends {
schema: {
[key in Key]: {
fields: infer Field;
};
};
export type InferSessionFromClient<O extends ClientOptions> = InferSession<
InferAuthFromClient<O> extends Auth ? InferAuthFromClient<O> : never
>;
export type InferUserFromClient<O extends ClientOptions> = InferUser<
InferAuthFromClient<O> extends Auth ? InferAuthFromClient<O> : never
>;
};
}
? Field extends Record<infer Key, FieldAttribute>
? {
[key in Key as Field[key]["required"] extends false
? never
: Field[key]["defaultValue"] extends
| boolean
| string
| number
| Date
| Function
? key
: never]: InferFieldOutput<Field[key]>;
} & {
[key in Key as Field[key]["returned"] extends false
? never
: key]?: InferFieldOutput<Field[key]>;
}
: {}
: {}
: {}
: {};

View File

@@ -1,28 +0,0 @@
import type { BetterAuthClientPlugin, OAuthProviderList } from "../../types";
export const client = () => {
return {
id: "last-used",
fetchPlugins: [
{
id: "last-used",
name: "Last Used",
init(url, options) {
if (url.startsWith("/sign-in")) {
let lastUsed = "";
if (url === "/sign-in/social") {
lastUsed = options?.body?.provider;
} else {
lastUsed = url.replace("/sign-in/", "");
}
localStorage.setItem("last-used", lastUsed);
}
return {
url,
options,
};
},
},
],
} satisfies BetterAuthClientPlugin;
};

View File

@@ -27,3 +27,9 @@ export type RequiredKeysOf<BaseType extends object> = Exclude<
export type HasRequiredKeys<BaseType extends object> =
RequiredKeysOf<BaseType> extends never ? false : true;
export type WithoutEmpty<T> = T extends T ? ({} extends T ? never : T) : never;
export type StripEmptyObjects<T> = T extends { [K in keyof T]: never }
? never
: T extends object
? { [K in keyof T as T[K] extends never ? never : K]: T[K] }
: T;

View File

@@ -2,7 +2,11 @@ import type { BetterAuthOptions } from ".";
import type { Session, User } from "../db/schema";
import type { Auth } from "../auth";
import type { FieldAttribute, InferFieldOutput } from "../db";
import type { Prettify, UnionToIntersection } from "./helper";
import type {
Prettify,
StripEmptyObjects,
UnionToIntersection,
} from "./helper";
import type { BetterAuthPlugin } from "./plugins";
type AdditionalSessionFields<Options extends BetterAuthOptions> =
@@ -31,8 +35,7 @@ type AdditionalUserFields<Options extends BetterAuthOptions> =
};
}
? Field extends Record<infer Key, FieldAttribute>
? Prettify<
{
? {
[key in Key as Field[key]["required"] extends false
? never
: Field[key]["defaultValue"] extends
@@ -48,18 +51,21 @@ type AdditionalUserFields<Options extends BetterAuthOptions> =
? never
: key]?: InferFieldOutput<Field[key]>;
}
>
: {}
: {}
: {};
export type InferUser<O extends BetterAuthOptions | Auth> = UnionToIntersection<
StripEmptyObjects<
Prettify<
User &
(O extends BetterAuthOptions
? AdditionalUserFields<O>
: O extends Auth
? AdditionalUserFields<O["options"]>
: {})
>
>
>;
export type InferSession<O extends BetterAuthOptions | Auth> =

2
pnpm-lock.yaml generated
View File

@@ -1271,7 +1271,7 @@ importers:
specifier: ^0.33.0
version: 0.33.0(@prisma/client@5.20.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/react@18.3.9)(better-sqlite3@11.3.0)(kysely@0.27.4)(mysql2@3.11.3)(pg@8.13.0)(prisma@5.20.0)(react@18.3.1)
happy-dom:
specifier: ^15.7.3
specifier: ^15.7.4
version: 15.7.4
hono:
specifier: ^4.5.4