feat: support custom schema merging in SIWE plugin (#4138)

This commit is contained in:
Alex Yang
2025-08-21 16:00:56 -07:00
committed by GitHub
parent 127ad5d326
commit 09a04517eb
2 changed files with 72 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
import { APIError, createAuthEndpoint } from "../../api";
import { setSessionCookie } from "../../cookies";
import { z } from "zod";
import type { BetterAuthPlugin } from "../../types";
import type { BetterAuthPlugin, InferOptionSchema } from "../../types";
import type {
ENSLookupArgs,
ENSLookupResult,
@@ -12,6 +12,7 @@ import type { User } from "../../types";
import { schema } from "./schema";
import { getOrigin } from "../../utils/url";
import { toChecksumAddress } from "../../utils/hashing";
import { mergeSchema } from "../../db/schema";
export interface SIWEPluginOptions {
domain: string;
@@ -20,12 +21,13 @@ export interface SIWEPluginOptions {
getNonce: () => Promise<string>;
verifyMessage: (args: SIWEVerifyMessageArgs) => Promise<boolean>;
ensLookup?: (args: ENSLookupArgs) => Promise<ENSLookupResult>;
schema?: InferOptionSchema<typeof schema>;
}
export const siwe = (options: SIWEPluginOptions) =>
({
id: "siwe",
schema,
schema: mergeSchema(schema, options?.schema),
endpoints: {
getSiweNonce: createAuthEndpoint(
"/siwe/nonce",

View File

@@ -606,6 +606,74 @@ describe("siwe", async (it) => {
expect(usersWithTestAddress.length).toBe(1); // Only one user should have this address
});
it("should support custom schema with mergeSchema", async () => {
const { client, auth } = await getTestInstance(
{
logger: {
level: "debug",
},
plugins: [
siwe({
domain,
async getNonce() {
return "A1b2C3d4E5f6G7h8J";
},
async verifyMessage({ message, signature }) {
return (
signature === "valid_signature" && message === "valid_message"
);
},
schema: {
walletAddress: {
modelName: "wallet_address",
fields: {
userId: "user_id",
address: "wallet_address",
chainId: "chain_id",
isPrimary: "is_primary",
createdAt: "created_at",
},
},
},
}),
],
},
{ clientOptions: { plugins: [siweClient()] } },
);
const testAddress = "0x000000000000000000000000000000000000dEaD";
const testChainId = 1;
// Create account with custom schema
await client.siwe.nonce({
walletAddress: testAddress,
chainId: testChainId,
});
const result = await client.siwe.verify({
message: "valid_message",
signature: "valid_signature",
walletAddress: testAddress,
chainId: testChainId,
});
expect(result.error).toBeNull();
expect(result.data?.success).toBe(true);
const context = await auth.$context;
const walletAddresses: any[] = await context.adapter.findMany({
model: "walletAddress",
where: [
{ field: "address", operator: "eq", value: testAddress },
{ field: "chainId", operator: "eq", value: testChainId },
],
});
expect(walletAddresses.length).toBe(1);
expect(walletAddresses[0]?.address).toBe(testAddress);
expect(walletAddresses[0]?.chainId).toBe(testChainId);
expect(walletAddresses[0]?.isPrimary).toBe(true);
expect(walletAddresses[0]?.userId).toBeDefined();
expect(walletAddresses[0]?.createdAt).toBeDefined();
});
it("should allow same address on different chains for same user", async () => {
const { client, auth } = await getTestInstance(
{