mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 12:27:43 +00:00
refactor: move db schema to core (#4918)
This commit is contained in:
@@ -14,7 +14,7 @@ import type {
|
|||||||
AdapterTestDebugLogs,
|
AdapterTestDebugLogs,
|
||||||
CleanedWhere,
|
CleanedWhere,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import type { FieldAttribute } from "../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
|
|
||||||
let debugLogs: any[] = [];
|
let debugLogs: any[] = [];
|
||||||
@@ -303,7 +303,7 @@ export const createAdapterFactory =
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
} satisfies FieldAttribute;
|
} satisfies DBFieldAttribute;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFieldAttributes = ({
|
const getFieldAttributes = ({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { FieldAttribute } from "../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import type { BetterAuthDbSchema } from "../../db/get-tables";
|
import type { BetterAuthDBSchema } from "@better-auth/core/db";
|
||||||
import type {
|
import type {
|
||||||
AdapterSchemaCreation,
|
AdapterSchemaCreation,
|
||||||
BetterAuthOptions,
|
BetterAuthOptions,
|
||||||
@@ -164,7 +164,7 @@ export interface AdapterFactoryConfig {
|
|||||||
/**
|
/**
|
||||||
* The fields of the model.
|
* The fields of the model.
|
||||||
*/
|
*/
|
||||||
fieldAttributes: FieldAttribute;
|
fieldAttributes: DBFieldAttribute;
|
||||||
/**
|
/**
|
||||||
* The field to transform.
|
* The field to transform.
|
||||||
*/
|
*/
|
||||||
@@ -180,7 +180,7 @@ export interface AdapterFactoryConfig {
|
|||||||
/**
|
/**
|
||||||
* The schema of the user's Better-Auth instance.
|
* The schema of the user's Better-Auth instance.
|
||||||
*/
|
*/
|
||||||
schema: BetterAuthDbSchema;
|
schema: BetterAuthDBSchema;
|
||||||
/**
|
/**
|
||||||
* The options of the user's Better-Auth instance.
|
* The options of the user's Better-Auth instance.
|
||||||
*/
|
*/
|
||||||
@@ -196,7 +196,7 @@ export interface AdapterFactoryConfig {
|
|||||||
/**
|
/**
|
||||||
* The fields of the model.
|
* The fields of the model.
|
||||||
*/
|
*/
|
||||||
fieldAttributes: FieldAttribute;
|
fieldAttributes: DBFieldAttribute;
|
||||||
/**
|
/**
|
||||||
* The field to transform.
|
* The field to transform.
|
||||||
*/
|
*/
|
||||||
@@ -212,7 +212,7 @@ export interface AdapterFactoryConfig {
|
|||||||
/**
|
/**
|
||||||
* The schema of the user's Better-Auth instance.
|
* The schema of the user's Better-Auth instance.
|
||||||
*/
|
*/
|
||||||
schema: BetterAuthDbSchema;
|
schema: BetterAuthDBSchema;
|
||||||
/**
|
/**
|
||||||
* The options of the user's Better-Auth instance.
|
* The options of the user's Better-Auth instance.
|
||||||
*/
|
*/
|
||||||
@@ -246,7 +246,7 @@ export type AdapterFactoryCustomizeAdapterCreator = (config: {
|
|||||||
/**
|
/**
|
||||||
* The schema of the user's Better-Auth instance.
|
* The schema of the user's Better-Auth instance.
|
||||||
*/
|
*/
|
||||||
schema: BetterAuthDbSchema;
|
schema: BetterAuthDBSchema;
|
||||||
/**
|
/**
|
||||||
* The debug log function.
|
* The debug log function.
|
||||||
*
|
*
|
||||||
@@ -303,7 +303,7 @@ export type AdapterFactoryCustomizeAdapterCreator = (config: {
|
|||||||
}: {
|
}: {
|
||||||
model: string;
|
model: string;
|
||||||
field: string;
|
field: string;
|
||||||
}) => FieldAttribute;
|
}) => DBFieldAttribute;
|
||||||
}) => CustomAdapter;
|
}) => CustomAdapter;
|
||||||
|
|
||||||
export interface CustomAdapter {
|
export interface CustomAdapter {
|
||||||
@@ -377,7 +377,7 @@ export interface CustomAdapter {
|
|||||||
/**
|
/**
|
||||||
* The tables from the user's Better-Auth instance schema.
|
* The tables from the user's Better-Auth instance schema.
|
||||||
*/
|
*/
|
||||||
tables: BetterAuthDbSchema;
|
tables: BetterAuthDBSchema;
|
||||||
}) => Promise<AdapterSchemaCreation>;
|
}) => Promise<AdapterSchemaCreation>;
|
||||||
/**
|
/**
|
||||||
* Your adapter's options.
|
* Your adapter's options.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { FieldAttribute } from "../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export function withApplyDefault(
|
export function withApplyDefault(
|
||||||
value: any,
|
value: any,
|
||||||
field: FieldAttribute,
|
field: DBFieldAttribute,
|
||||||
action: "create" | "update",
|
action: "create" | "update",
|
||||||
) {
|
) {
|
||||||
if (action === "update") {
|
if (action === "update") {
|
||||||
|
|||||||
@@ -1,118 +1,13 @@
|
|||||||
import type { ZodType } from "zod";
|
import type {
|
||||||
|
DBFieldAttribute,
|
||||||
|
DBFieldAttributeConfig,
|
||||||
|
DBFieldType,
|
||||||
|
} from "@better-auth/core/db";
|
||||||
import type { BetterAuthOptions } from "../types";
|
import type { BetterAuthOptions } from "../types";
|
||||||
import type { LiteralString } from "../types/helper";
|
|
||||||
|
|
||||||
export type FieldType =
|
|
||||||
| "string"
|
|
||||||
| "number"
|
|
||||||
| "boolean"
|
|
||||||
| "date"
|
|
||||||
| "json"
|
|
||||||
| `${"string" | "number"}[]`
|
|
||||||
| Array<LiteralString>;
|
|
||||||
|
|
||||||
type Primitive =
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| Date
|
|
||||||
| null
|
|
||||||
| undefined
|
|
||||||
| string[]
|
|
||||||
| number[];
|
|
||||||
|
|
||||||
export type FieldAttributeConfig<T extends FieldType = FieldType> = {
|
|
||||||
/**
|
|
||||||
* If the field should be required on a new record.
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
required?: boolean;
|
|
||||||
/**
|
|
||||||
* If the value should be returned on a response body.
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
returned?: boolean;
|
|
||||||
/**
|
|
||||||
* If a value should be provided when creating a new record.
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
input?: boolean;
|
|
||||||
/**
|
|
||||||
* Default value for the field
|
|
||||||
*
|
|
||||||
* Note: This will not create a default value on the database level. It will only
|
|
||||||
* be used when creating a new record.
|
|
||||||
*/
|
|
||||||
defaultValue?: Primitive | (() => Primitive);
|
|
||||||
/**
|
|
||||||
* Update value for the field
|
|
||||||
*
|
|
||||||
* Note: This will create an onUpdate trigger on the database level for supported adapters.
|
|
||||||
* It will be called when updating a record.
|
|
||||||
*/
|
|
||||||
onUpdate?: () => Primitive;
|
|
||||||
/**
|
|
||||||
* transform the value before storing it.
|
|
||||||
*/
|
|
||||||
transform?: {
|
|
||||||
input?: (value: Primitive) => Primitive | Promise<Primitive>;
|
|
||||||
output?: (value: Primitive) => Primitive | Promise<Primitive>;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Reference to another model.
|
|
||||||
*/
|
|
||||||
references?: {
|
|
||||||
/**
|
|
||||||
* The model to reference.
|
|
||||||
*/
|
|
||||||
model: string;
|
|
||||||
/**
|
|
||||||
* The field on the referenced model.
|
|
||||||
*/
|
|
||||||
field: string;
|
|
||||||
/**
|
|
||||||
* The action to perform when the reference is deleted.
|
|
||||||
* @default "cascade"
|
|
||||||
*/
|
|
||||||
onDelete?:
|
|
||||||
| "no action"
|
|
||||||
| "restrict"
|
|
||||||
| "cascade"
|
|
||||||
| "set null"
|
|
||||||
| "set default";
|
|
||||||
};
|
|
||||||
unique?: boolean;
|
|
||||||
/**
|
|
||||||
* If the field should be a bigint on the database instead of integer.
|
|
||||||
*/
|
|
||||||
bigint?: boolean;
|
|
||||||
/**
|
|
||||||
* A zod schema to validate the value.
|
|
||||||
*/
|
|
||||||
validator?: {
|
|
||||||
input?: ZodType;
|
|
||||||
output?: ZodType;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* The name of the field on the database.
|
|
||||||
*/
|
|
||||||
fieldName?: string;
|
|
||||||
/**
|
|
||||||
* If the field should be sortable.
|
|
||||||
*
|
|
||||||
* applicable only for `text` type.
|
|
||||||
* It's useful to mark fields varchar instead of text.
|
|
||||||
*/
|
|
||||||
sortable?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FieldAttribute<T extends FieldType = FieldType> = {
|
|
||||||
type: T;
|
|
||||||
} & FieldAttributeConfig<T>;
|
|
||||||
|
|
||||||
export const createFieldAttribute = <
|
export const createFieldAttribute = <
|
||||||
T extends FieldType,
|
T extends DBFieldType,
|
||||||
C extends Omit<FieldAttributeConfig<T>, "type">,
|
C extends DBFieldAttributeConfig,
|
||||||
>(
|
>(
|
||||||
type: T,
|
type: T,
|
||||||
config?: C,
|
config?: C,
|
||||||
@@ -120,10 +15,10 @@ export const createFieldAttribute = <
|
|||||||
return {
|
return {
|
||||||
type,
|
type,
|
||||||
...config,
|
...config,
|
||||||
} satisfies FieldAttribute<T>;
|
} satisfies DBFieldAttribute<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InferValueType<T extends FieldType> = T extends "string"
|
export type InferValueType<T extends DBFieldType> = T extends "string"
|
||||||
? string
|
? string
|
||||||
: T extends "number"
|
: T extends "number"
|
||||||
? number
|
? number
|
||||||
@@ -141,7 +36,7 @@ export type InferValueType<T extends FieldType> = T extends "string"
|
|||||||
|
|
||||||
export type InferFieldsOutput<Field> = Field extends Record<
|
export type InferFieldsOutput<Field> = Field extends Record<
|
||||||
infer Key,
|
infer Key,
|
||||||
FieldAttribute
|
DBFieldAttribute
|
||||||
>
|
>
|
||||||
? {
|
? {
|
||||||
[key in Key as Field[key]["required"] extends false
|
[key in Key as Field[key]["required"] extends false
|
||||||
@@ -158,7 +53,7 @@ export type InferFieldsOutput<Field> = Field extends Record<
|
|||||||
|
|
||||||
export type InferFieldsInput<Field> = Field extends Record<
|
export type InferFieldsInput<Field> = Field extends Record<
|
||||||
infer Key,
|
infer Key,
|
||||||
FieldAttribute
|
DBFieldAttribute
|
||||||
>
|
>
|
||||||
? {
|
? {
|
||||||
[key in Key as Field[key]["required"] extends false
|
[key in Key as Field[key]["required"] extends false
|
||||||
@@ -181,7 +76,7 @@ export type InferFieldsInput<Field> = Field extends Record<
|
|||||||
*/
|
*/
|
||||||
export type InferFieldsInputClient<Field> = Field extends Record<
|
export type InferFieldsInputClient<Field> = Field extends Record<
|
||||||
infer Key,
|
infer Key,
|
||||||
FieldAttribute
|
DBFieldAttribute
|
||||||
>
|
>
|
||||||
? {
|
? {
|
||||||
[key in Key as Field[key]["required"] extends false
|
[key in Key as Field[key]["required"] extends false
|
||||||
@@ -202,18 +97,18 @@ export type InferFieldsInputClient<Field> = Field extends Record<
|
|||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
type InferFieldOutput<T extends FieldAttribute> = T["returned"] extends false
|
type InferFieldOutput<T extends DBFieldAttribute> = T["returned"] extends false
|
||||||
? never
|
? never
|
||||||
: T["required"] extends false
|
: T["required"] extends false
|
||||||
? InferValueType<T["type"]> | undefined | null
|
? InferValueType<T["type"]> | undefined | null
|
||||||
: InferValueType<T["type"]>;
|
: InferValueType<T["type"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a Record<string, FieldAttribute> to an object type
|
* Converts a Record<string, DBFieldAttribute> to an object type
|
||||||
* with keys and value types inferred from FieldAttribute["type"].
|
* with keys and value types inferred from DBFieldAttribute["type"].
|
||||||
*/
|
*/
|
||||||
export type FieldAttributeToObject<
|
export type FieldAttributeToObject<
|
||||||
Fields extends Record<string, FieldAttribute>,
|
Fields extends Record<string, DBFieldAttribute>,
|
||||||
> = AddOptionalFields<
|
> = AddOptionalFields<
|
||||||
{
|
{
|
||||||
[K in keyof Fields]: InferValueType<Fields[K]["type"]>;
|
[K in keyof Fields]: InferValueType<Fields[K]["type"]>;
|
||||||
@@ -223,7 +118,7 @@ export type FieldAttributeToObject<
|
|||||||
|
|
||||||
type AddOptionalFields<
|
type AddOptionalFields<
|
||||||
T extends Record<string, any>,
|
T extends Record<string, any>,
|
||||||
Fields extends Record<keyof T, FieldAttribute>,
|
Fields extends Record<keyof T, DBFieldAttribute>,
|
||||||
> = {
|
> = {
|
||||||
// Required fields: required === true
|
// Required fields: required === true
|
||||||
[K in keyof T as Fields[K] extends { required: true } ? K : never]: T[K];
|
[K in keyof T as Fields[K] extends { required: true } ? K : never]: T[K];
|
||||||
@@ -244,14 +139,14 @@ export type InferAdditionalFieldsFromPluginOptions<
|
|||||||
Options extends {
|
Options extends {
|
||||||
schema?: {
|
schema?: {
|
||||||
[key in SchemaName]?: {
|
[key in SchemaName]?: {
|
||||||
additionalFields?: Record<string, FieldAttribute>;
|
additionalFields?: Record<string, DBFieldAttribute>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
isClientSide extends boolean = true,
|
isClientSide extends boolean = true,
|
||||||
> = Options["schema"] extends {
|
> = Options["schema"] extends {
|
||||||
[key in SchemaName]?: {
|
[key in SchemaName]?: {
|
||||||
additionalFields: infer Field extends Record<string, FieldAttribute>;
|
additionalFields: infer Field extends Record<string, DBFieldAttribute>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
? isClientSide extends true
|
? isClientSide extends true
|
||||||
@@ -259,14 +154,14 @@ export type InferAdditionalFieldsFromPluginOptions<
|
|||||||
: FieldAttributeToObject<Field>
|
: FieldAttributeToObject<Field>
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
type RemoveFieldsWithInputFalse<T extends Record<string, FieldAttribute>> = {
|
type RemoveFieldsWithInputFalse<T extends Record<string, DBFieldAttribute>> = {
|
||||||
[K in keyof T as T[K]["input"] extends false ? never : K]: T[K];
|
[K in keyof T as T[K]["input"] extends false ? never : K]: T[K];
|
||||||
};
|
};
|
||||||
|
|
||||||
type InferFieldInput<T extends FieldAttribute> = InferValueType<T["type"]>;
|
type InferFieldInput<T extends DBFieldAttribute> = InferValueType<T["type"]>;
|
||||||
|
|
||||||
export type PluginFieldAttribute = Omit<
|
export type PluginFieldAttribute = Omit<
|
||||||
FieldAttribute,
|
DBFieldAttribute,
|
||||||
"transform" | "defaultValue" | "hashValue"
|
"transform" | "defaultValue" | "hashValue"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type {
|
|||||||
AlterTableColumnAlteringBuilder,
|
AlterTableColumnAlteringBuilder,
|
||||||
CreateTableBuilder,
|
CreateTableBuilder,
|
||||||
} from "kysely";
|
} from "kysely";
|
||||||
import type { FieldAttribute, FieldType } from ".";
|
import type { DBFieldAttribute, DBFieldType } from "@better-auth/core/db";
|
||||||
import { sql } from "kysely";
|
import { sql } from "kysely";
|
||||||
import { createLogger } from "../utils/logger";
|
import { createLogger } from "../utils/logger";
|
||||||
import type { BetterAuthOptions } from "../types";
|
import type { BetterAuthOptions } from "../types";
|
||||||
@@ -66,7 +66,7 @@ const map = {
|
|||||||
|
|
||||||
export function matchType(
|
export function matchType(
|
||||||
columnDataType: string,
|
columnDataType: string,
|
||||||
fieldType: FieldType,
|
fieldType: DBFieldType,
|
||||||
dbType: KyselyDatabaseType,
|
dbType: KyselyDatabaseType,
|
||||||
) {
|
) {
|
||||||
function normalize(type: string) {
|
function normalize(type: string) {
|
||||||
@@ -104,12 +104,12 @@ export async function getMigrations(config: BetterAuthOptions) {
|
|||||||
const tableMetadata = await db.introspection.getTables();
|
const tableMetadata = await db.introspection.getTables();
|
||||||
const toBeCreated: {
|
const toBeCreated: {
|
||||||
table: string;
|
table: string;
|
||||||
fields: Record<string, FieldAttribute>;
|
fields: Record<string, DBFieldAttribute>;
|
||||||
order: number;
|
order: number;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
const toBeAdded: {
|
const toBeAdded: {
|
||||||
table: string;
|
table: string;
|
||||||
fields: Record<string, FieldAttribute>;
|
fields: Record<string, DBFieldAttribute>;
|
||||||
order: number;
|
order: number;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ export async function getMigrations(config: BetterAuthOptions) {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let toBeAddedFields: Record<string, FieldAttribute> = {};
|
let toBeAddedFields: Record<string, DBFieldAttribute> = {};
|
||||||
for (const [fieldName, field] of Object.entries(value.fields)) {
|
for (const [fieldName, field] of Object.entries(value.fields)) {
|
||||||
const column = table.columns.find((c) => c.name === fieldName);
|
const column = table.columns.find((c) => c.name === fieldName);
|
||||||
if (!column) {
|
if (!column) {
|
||||||
@@ -171,7 +171,7 @@ export async function getMigrations(config: BetterAuthOptions) {
|
|||||||
| CreateTableBuilder<string, string>
|
| CreateTableBuilder<string, string>
|
||||||
)[] = [];
|
)[] = [];
|
||||||
|
|
||||||
function getType(field: FieldAttribute, fieldName: string) {
|
function getType(field: DBFieldAttribute, fieldName: string) {
|
||||||
const type = field.type;
|
const type = field.type;
|
||||||
const typeMap = {
|
const typeMap = {
|
||||||
string: {
|
string: {
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import { getAuthTables, type FieldAttribute } from ".";
|
import { getAuthTables } from ".";
|
||||||
import type { BetterAuthOptions } from "../types";
|
import type { BetterAuthOptions } from "../types";
|
||||||
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export function getSchema(config: BetterAuthOptions) {
|
export function getSchema(config: BetterAuthOptions) {
|
||||||
const tables = getAuthTables(config);
|
const tables = getAuthTables(config);
|
||||||
let schema: Record<
|
let schema: Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
fields: Record<string, FieldAttribute>;
|
fields: Record<string, DBFieldAttribute>;
|
||||||
order: number;
|
order: number;
|
||||||
}
|
}
|
||||||
> = {};
|
> = {};
|
||||||
for (const key in tables) {
|
for (const key in tables) {
|
||||||
const table = tables[key]!;
|
const table = tables[key]!;
|
||||||
const fields = table.fields;
|
const fields = table.fields;
|
||||||
let actualFields: Record<string, FieldAttribute> = {};
|
let actualFields: Record<string, DBFieldAttribute> = {};
|
||||||
Object.entries(fields).forEach(([key, field]) => {
|
Object.entries(fields).forEach(([key, field]) => {
|
||||||
actualFields[field.fieldName || key] = field;
|
actualFields[field.fieldName || key] = field;
|
||||||
if (field.references) {
|
if (field.references) {
|
||||||
|
|||||||
@@ -1,32 +1,12 @@
|
|||||||
import type { FieldAttribute } from ".";
|
|
||||||
import type { BetterAuthOptions } from "../types";
|
import type { BetterAuthOptions } from "../types";
|
||||||
|
import type {
|
||||||
export type BetterAuthDbSchema = Record<
|
BetterAuthDBSchema,
|
||||||
string,
|
DBFieldAttribute,
|
||||||
{
|
} from "@better-auth/core/db";
|
||||||
/**
|
|
||||||
* The name of the table in the database
|
|
||||||
*/
|
|
||||||
modelName: string;
|
|
||||||
/**
|
|
||||||
* The fields of the table
|
|
||||||
*/
|
|
||||||
fields: Record<string, FieldAttribute>;
|
|
||||||
/**
|
|
||||||
* Whether to disable migrations for this table
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
disableMigrations?: boolean;
|
|
||||||
/**
|
|
||||||
* The order of the table
|
|
||||||
*/
|
|
||||||
order?: number;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const getAuthTables = (
|
export const getAuthTables = (
|
||||||
options: BetterAuthOptions,
|
options: BetterAuthOptions,
|
||||||
): BetterAuthDbSchema => {
|
): BetterAuthDBSchema => {
|
||||||
const pluginSchema = (options.plugins ?? []).reduce(
|
const pluginSchema = (options.plugins ?? []).reduce(
|
||||||
(acc, plugin) => {
|
(acc, plugin) => {
|
||||||
const schema = plugin.schema;
|
const schema = plugin.schema;
|
||||||
@@ -44,7 +24,7 @@ export const getAuthTables = (
|
|||||||
},
|
},
|
||||||
{} as Record<
|
{} as Record<
|
||||||
string,
|
string,
|
||||||
{ fields: Record<string, FieldAttribute>; modelName: string }
|
{ fields: Record<string, DBFieldAttribute>; modelName: string }
|
||||||
>,
|
>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,7 +48,7 @@ export const getAuthTables = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} satisfies BetterAuthDbSchema;
|
} satisfies BetterAuthDBSchema;
|
||||||
|
|
||||||
const { user, session, account, ...pluginTables } = pluginSchema;
|
const { user, session, account, ...pluginTables } = pluginSchema;
|
||||||
|
|
||||||
@@ -124,7 +104,7 @@ export const getAuthTables = (
|
|||||||
},
|
},
|
||||||
order: 2,
|
order: 2,
|
||||||
},
|
},
|
||||||
} satisfies BetterAuthDbSchema;
|
} satisfies BetterAuthDBSchema;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
@@ -290,5 +270,5 @@ export const getAuthTables = (
|
|||||||
},
|
},
|
||||||
...pluginTables,
|
...pluginTables,
|
||||||
...(shouldAddRateLimitTable ? rateLimitTable : {}),
|
...(shouldAddRateLimitTable ? rateLimitTable : {}),
|
||||||
} satisfies BetterAuthDbSchema;
|
} satisfies BetterAuthDBSchema;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from "@better-auth/core/db";
|
||||||
export * from "./internal-adapter";
|
export * from "./internal-adapter";
|
||||||
export * from "./field";
|
export * from "./field";
|
||||||
export * from "./get-tables";
|
export * from "./get-tables";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import type { FieldAttribute } from ".";
|
|
||||||
import type { AuthPluginSchema } from "../types/plugins";
|
import type { AuthPluginSchema } from "../types/plugins";
|
||||||
import type { BetterAuthOptions } from "../types/options";
|
import type { BetterAuthOptions } from "../types/options";
|
||||||
import { APIError } from "better-call";
|
import { APIError } from "better-call";
|
||||||
import type { Account, Session, User } from "../types";
|
import type { Account, Session, User } from "../types";
|
||||||
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export const coreSchema = z.object({
|
export const coreSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
@@ -60,7 +60,7 @@ export const verificationSchema = coreSchema.extend({
|
|||||||
export function parseOutputData<T extends Record<string, any>>(
|
export function parseOutputData<T extends Record<string, any>>(
|
||||||
data: T,
|
data: T,
|
||||||
schema: {
|
schema: {
|
||||||
fields: Record<string, FieldAttribute>;
|
fields: Record<string, DBFieldAttribute>;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const fields = schema.fields;
|
const fields = schema.fields;
|
||||||
@@ -80,7 +80,7 @@ export function parseOutputData<T extends Record<string, any>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAllFields(options: BetterAuthOptions, table: string) {
|
export function getAllFields(options: BetterAuthOptions, table: string) {
|
||||||
let schema: Record<string, FieldAttribute> = {
|
let schema: Record<string, DBFieldAttribute> = {
|
||||||
...(table === "user" ? options.user?.additionalFields : {}),
|
...(table === "user" ? options.user?.additionalFields : {}),
|
||||||
...(table === "session" ? options.session?.additionalFields : {}),
|
...(table === "session" ? options.session?.additionalFields : {}),
|
||||||
};
|
};
|
||||||
@@ -119,7 +119,7 @@ export function parseSessionOutput(
|
|||||||
export function parseInputData<T extends Record<string, any>>(
|
export function parseInputData<T extends Record<string, any>>(
|
||||||
data: T,
|
data: T,
|
||||||
schema: {
|
schema: {
|
||||||
fields: Record<string, FieldAttribute>;
|
fields: Record<string, DBFieldAttribute>;
|
||||||
action?: "create" | "update";
|
action?: "create" | "update";
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import type { ZodType } from "zod";
|
import type { ZodType } from "zod";
|
||||||
import type { FieldAttribute } from ".";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export function toZodSchema<
|
export function toZodSchema<
|
||||||
Fields extends Record<string, FieldAttribute | never>,
|
Fields extends Record<string, DBFieldAttribute | never>,
|
||||||
IsClientSide extends boolean,
|
IsClientSide extends boolean,
|
||||||
>({
|
>({
|
||||||
fields,
|
fields,
|
||||||
@@ -56,14 +56,14 @@ export function toZodSchema<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type FieldAttributeToSchema<
|
export type FieldAttributeToSchema<
|
||||||
Field extends FieldAttribute | Record<string, never>,
|
Field extends DBFieldAttribute | Record<string, never>,
|
||||||
// if it's client side, then field attributes of `input` that are false should be removed
|
// if it's client side, then field attributes of `input` that are false should be removed
|
||||||
isClientSide extends boolean = false,
|
isClientSide extends boolean = false,
|
||||||
> = Field extends { type: any }
|
> = Field extends { type: any }
|
||||||
? GetInput<isClientSide, Field, GetRequired<Field, GetType<Field>>>
|
? GetInput<isClientSide, Field, GetRequired<Field, GetType<Field>>>
|
||||||
: Record<string, never>;
|
: Record<string, never>;
|
||||||
|
|
||||||
type GetType<F extends FieldAttribute> = F extends {
|
type GetType<F extends DBFieldAttribute> = F extends {
|
||||||
type: "string";
|
type: "string";
|
||||||
}
|
}
|
||||||
? z.ZodString
|
? z.ZodString
|
||||||
@@ -76,7 +76,7 @@ type GetType<F extends FieldAttribute> = F extends {
|
|||||||
: z.ZodAny;
|
: z.ZodAny;
|
||||||
|
|
||||||
type GetRequired<
|
type GetRequired<
|
||||||
F extends FieldAttribute,
|
F extends DBFieldAttribute,
|
||||||
Schema extends z.core.SomeType,
|
Schema extends z.core.SomeType,
|
||||||
> = F extends {
|
> = F extends {
|
||||||
required: true;
|
required: true;
|
||||||
@@ -86,7 +86,7 @@ type GetRequired<
|
|||||||
|
|
||||||
type GetInput<
|
type GetInput<
|
||||||
isClientSide extends boolean,
|
isClientSide extends boolean,
|
||||||
Field extends FieldAttribute,
|
Field extends DBFieldAttribute,
|
||||||
Schema extends z.core.SomeType,
|
Schema extends z.core.SomeType,
|
||||||
> = Field extends {
|
> = Field extends {
|
||||||
input: false;
|
input: false;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { getAuthTables, type FieldAttribute } from ".";
|
import { getAuthTables } from ".";
|
||||||
import { BetterAuthError } from "../error";
|
import { BetterAuthError } from "../error";
|
||||||
import type { Adapter, BetterAuthOptions } from "../types";
|
import type { Adapter, BetterAuthOptions } from "../types";
|
||||||
import { createKyselyAdapter } from "../adapters/kysely-adapter/dialect";
|
import { createKyselyAdapter } from "../adapters/kysely-adapter/dialect";
|
||||||
import { kyselyAdapter } from "../adapters/kysely-adapter";
|
import { kyselyAdapter } from "../adapters/kysely-adapter";
|
||||||
import { memoryAdapter, type MemoryDB } from "../adapters/memory-adapter";
|
import { memoryAdapter, type MemoryDB } from "../adapters/memory-adapter";
|
||||||
import { logger } from "../utils";
|
import { logger } from "../utils";
|
||||||
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export async function getAdapter(options: BetterAuthOptions): Promise<Adapter> {
|
export async function getAdapter(options: BetterAuthOptions): Promise<Adapter> {
|
||||||
if (!options.database) {
|
if (!options.database) {
|
||||||
@@ -37,7 +38,7 @@ export async function getAdapter(options: BetterAuthOptions): Promise<Adapter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function convertToDB<T extends Record<string, any>>(
|
export function convertToDB<T extends Record<string, any>>(
|
||||||
fields: Record<string, FieldAttribute>,
|
fields: Record<string, DBFieldAttribute>,
|
||||||
values: T,
|
values: T,
|
||||||
) {
|
) {
|
||||||
let result: Record<string, any> = values.id
|
let result: Record<string, any> = values.id
|
||||||
@@ -57,7 +58,7 @@ export function convertToDB<T extends Record<string, any>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function convertFromDB<T extends Record<string, any>>(
|
export function convertFromDB<T extends Record<string, any>>(
|
||||||
fields: Record<string, FieldAttribute>,
|
fields: Record<string, DBFieldAttribute>,
|
||||||
values: T | null,
|
values: T | null,
|
||||||
) {
|
) {
|
||||||
if (!values) {
|
if (!values) {
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import { defu } from "defu";
|
import { defu } from "defu";
|
||||||
import { hashPassword, verifyPassword } from "./crypto/password";
|
import { hashPassword, verifyPassword } from "./crypto/password";
|
||||||
import {
|
import { createInternalAdapter, getAuthTables, getMigrations } from "./db";
|
||||||
type BetterAuthDbSchema,
|
|
||||||
createInternalAdapter,
|
|
||||||
getAuthTables,
|
|
||||||
getMigrations,
|
|
||||||
} from "./db";
|
|
||||||
import type { Entries } from "type-fest";
|
import type { Entries } from "type-fest";
|
||||||
import { getAdapter } from "./db/utils";
|
import { getAdapter } from "./db/utils";
|
||||||
import type {
|
import type {
|
||||||
@@ -37,6 +32,7 @@ import type { TelemetryEvent } from "./telemetry/types";
|
|||||||
import { getKyselyDatabaseType } from "./adapters/kysely-adapter";
|
import { getKyselyDatabaseType } from "./adapters/kysely-adapter";
|
||||||
import { checkEndpointConflicts } from "./api";
|
import { checkEndpointConflicts } from "./api";
|
||||||
import { isPromise } from "./utils/is-promise";
|
import { isPromise } from "./utils/is-promise";
|
||||||
|
import type { BetterAuthDBSchema } from "@better-auth/core/db";
|
||||||
|
|
||||||
export const init = async (options: BetterAuthOptions) => {
|
export const init = async (options: BetterAuthOptions) => {
|
||||||
const adapter = await getAdapter(options);
|
const adapter = await getAdapter(options);
|
||||||
@@ -245,7 +241,7 @@ export type AuthContext = {
|
|||||||
};
|
};
|
||||||
checkPassword: typeof checkPassword;
|
checkPassword: typeof checkPassword;
|
||||||
};
|
};
|
||||||
tables: BetterAuthDbSchema;
|
tables: BetterAuthDBSchema;
|
||||||
runMigrations: () => Promise<void>;
|
runMigrations: () => Promise<void>;
|
||||||
publishTelemetry: (event: TelemetryEvent) => Promise<void>;
|
publishTelemetry: (event: TelemetryEvent) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { FieldAttribute } from "../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import type { BetterAuthClientPlugin, BetterAuthOptions } from "../../types";
|
import type { BetterAuthClientPlugin, BetterAuthOptions } from "../../types";
|
||||||
import type { BetterAuthPlugin } from "../../types";
|
import type { BetterAuthPlugin } from "../../types";
|
||||||
|
|
||||||
@@ -6,10 +6,10 @@ export const inferAdditionalFields = <
|
|||||||
T,
|
T,
|
||||||
S extends {
|
S extends {
|
||||||
user?: {
|
user?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
session?: {
|
session?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
} = {},
|
} = {},
|
||||||
>(
|
>(
|
||||||
@@ -26,10 +26,10 @@ export const inferAdditionalFields = <
|
|||||||
type Plugin = Opts extends never
|
type Plugin = Opts extends never
|
||||||
? S extends {
|
? S extends {
|
||||||
user?: {
|
user?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
session?: {
|
session?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import type {
|
|||||||
} from "better-call";
|
} from "better-call";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import { getEndpoints } from "../../api";
|
import { getEndpoints } from "../../api";
|
||||||
import {
|
import { getAuthTables } from "../../db";
|
||||||
type FieldAttributeConfig,
|
|
||||||
type FieldType,
|
|
||||||
getAuthTables,
|
|
||||||
} from "../../db";
|
|
||||||
import type { AuthContext, BetterAuthOptions } from "../../types";
|
import type { AuthContext, BetterAuthOptions } from "../../types";
|
||||||
import type { FieldAttribute } from "../../db";
|
import type {
|
||||||
|
DBFieldAttribute,
|
||||||
|
DBFieldAttributeConfig,
|
||||||
|
DBFieldType,
|
||||||
|
} from "@better-auth/core/db";
|
||||||
|
|
||||||
export interface Path {
|
export interface Path {
|
||||||
get?: {
|
get?: {
|
||||||
@@ -81,8 +81,8 @@ function getTypeFromZodType(zodType: z.ZodType<any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FieldSchema = {
|
type FieldSchema = {
|
||||||
type: FieldType;
|
type: DBFieldType;
|
||||||
default?: FieldAttributeConfig["defaultValue"] | "Generated at runtime";
|
default?: DBFieldAttributeConfig["defaultValue"] | "Generated at runtime";
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ type OpenAPIModelSchema = {
|
|||||||
required?: string[];
|
required?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
function getFieldSchema(field: FieldAttribute) {
|
function getFieldSchema(field: DBFieldAttribute) {
|
||||||
const schema: FieldSchema = {
|
const schema: FieldSchema = {
|
||||||
type: field.type === "date" ? "string" : field.type,
|
type: field.type === "date" ? "string" : field.type,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
ownerAc,
|
ownerAc,
|
||||||
defaultRoles,
|
defaultRoles,
|
||||||
} from "./access";
|
} from "./access";
|
||||||
import type { FieldAttribute } from "../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import type { BetterAuthOptions, BetterAuthPlugin } from "../../types";
|
import type { BetterAuthOptions, BetterAuthPlugin } from "../../types";
|
||||||
import type { OrganizationOptions } from "./types";
|
import type { OrganizationOptions } from "./types";
|
||||||
import type { HasPermissionBaseInput } from "./permission";
|
import type { HasPermissionBaseInput } from "./permission";
|
||||||
@@ -47,27 +47,27 @@ interface OrganizationClientOptions {
|
|||||||
schema?: {
|
schema?: {
|
||||||
organization?: {
|
organization?: {
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
member?: {
|
member?: {
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
invitation?: {
|
invitation?: {
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
team?: {
|
team?: {
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
organizationRole?: {
|
organizationRole?: {
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { inferOrgAdditionalFields, organizationClient } from "../client";
|
|||||||
import { createAccessControl } from "../../access";
|
import { createAccessControl } from "../../access";
|
||||||
import { adminAc, defaultStatements, memberAc, ownerAc } from "../access";
|
import { adminAc, defaultStatements, memberAc, ownerAc } from "../access";
|
||||||
import { parseSetCookieHeader } from "../../../cookies";
|
import { parseSetCookieHeader } from "../../../cookies";
|
||||||
import type { FieldAttribute } from "../../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import { ORGANIZATION_ERROR_CODES } from "../error-codes";
|
import { ORGANIZATION_ERROR_CODES } from "../error-codes";
|
||||||
|
|
||||||
describe("dynamic access control", async (it) => {
|
describe("dynamic access control", async (it) => {
|
||||||
@@ -43,7 +43,7 @@ describe("dynamic access control", async (it) => {
|
|||||||
input: false,
|
input: false,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
} satisfies Record<string, FieldAttribute>;
|
} satisfies Record<string, DBFieldAttribute>;
|
||||||
|
|
||||||
const { auth, customFetchImpl, sessionSetter, signInWithTestUser } =
|
const { auth, customFetchImpl, sessionSetter, signInWithTestUser } =
|
||||||
await getTestInstance({
|
await getTestInstance({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { FieldAttribute } from "../../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import type { User, Session, AuthContext } from "../../types";
|
import type { User, Session, AuthContext } from "../../types";
|
||||||
import type { AccessControl, Role } from "../access";
|
import type { AccessControl, Role } from "../access";
|
||||||
import type {
|
import type {
|
||||||
@@ -257,7 +257,7 @@ export interface OrganizationOptions {
|
|||||||
[key in keyof Omit<Organization, "id">]?: string;
|
[key in keyof Omit<Organization, "id">]?: string;
|
||||||
};
|
};
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key in string]: FieldAttribute;
|
[key in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
member?: {
|
member?: {
|
||||||
@@ -266,7 +266,7 @@ export interface OrganizationOptions {
|
|||||||
[key in keyof Omit<Member, "id">]?: string;
|
[key in keyof Omit<Member, "id">]?: string;
|
||||||
};
|
};
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key in string]: FieldAttribute;
|
[key in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
invitation?: {
|
invitation?: {
|
||||||
@@ -275,7 +275,7 @@ export interface OrganizationOptions {
|
|||||||
[key in keyof Omit<Invitation, "id">]?: string;
|
[key in keyof Omit<Invitation, "id">]?: string;
|
||||||
};
|
};
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key in string]: FieldAttribute;
|
[key in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
team?: {
|
team?: {
|
||||||
@@ -284,7 +284,7 @@ export interface OrganizationOptions {
|
|||||||
[key in keyof Omit<Team, "id">]?: string;
|
[key in keyof Omit<Team, "id">]?: string;
|
||||||
};
|
};
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key in string]: FieldAttribute;
|
[key in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
teamMember?: {
|
teamMember?: {
|
||||||
@@ -299,7 +299,7 @@ export interface OrganizationOptions {
|
|||||||
[key in keyof Omit<OrganizationRole, "id">]?: string;
|
[key in keyof Omit<OrganizationRole, "id">]?: string;
|
||||||
};
|
};
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key in string]: FieldAttribute;
|
[key in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import type { BetterAuthPlugin } from "./plugins";
|
|||||||
import type { SocialProviderList, SocialProviders } from "../social-providers";
|
import type { SocialProviderList, SocialProviders } from "../social-providers";
|
||||||
import type { AdapterInstance, SecondaryStorage } from "./adapter";
|
import type { AdapterInstance, SecondaryStorage } from "./adapter";
|
||||||
import type { KyselyDatabaseType } from "../adapters/kysely-adapter/types";
|
import type { KyselyDatabaseType } from "../adapters/kysely-adapter/types";
|
||||||
import type { FieldAttribute } from "../db";
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
import type { Models, RateLimit } from "./models";
|
import type { Models, RateLimit } from "./models";
|
||||||
import type { AuthContext } from ".";
|
import type { AuthContext } from ".";
|
||||||
import type { CookieOptions } from "better-call";
|
import type { CookieOptions } from "better-call";
|
||||||
@@ -457,7 +457,7 @@ export type BetterAuthOptions = {
|
|||||||
* Additional fields for the session
|
* Additional fields for the session
|
||||||
*/
|
*/
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Changing email configuration
|
* Changing email configuration
|
||||||
@@ -567,7 +567,7 @@ export type BetterAuthOptions = {
|
|||||||
* Additional fields for the session
|
* Additional fields for the session
|
||||||
*/
|
*/
|
||||||
additionalFields?: {
|
additionalFields?: {
|
||||||
[key: string]: FieldAttribute;
|
[key: string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* By default if secondary storage is provided
|
* By default if secondary storage is provided
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { Migration } from "kysely";
|
import type { Migration } from "kysely";
|
||||||
import { type AuthMiddleware } from "../api/call";
|
import { type AuthMiddleware } from "../api/call";
|
||||||
import type { FieldAttribute } from "../db/field";
|
|
||||||
import type { HookEndpointContext } from ".";
|
import type { HookEndpointContext } from ".";
|
||||||
import type {
|
import type {
|
||||||
Awaitable,
|
Awaitable,
|
||||||
@@ -11,11 +10,12 @@ import type {
|
|||||||
|
|
||||||
import type { AuthContext, BetterAuthOptions } from ".";
|
import type { AuthContext, BetterAuthOptions } from ".";
|
||||||
import type { Endpoint, Middleware } from "better-call";
|
import type { Endpoint, Middleware } from "better-call";
|
||||||
|
import type { DBFieldAttribute } from "@better-auth/core/db";
|
||||||
|
|
||||||
export type AuthPluginSchema = {
|
export type AuthPluginSchema = {
|
||||||
[table in string]: {
|
[table in string]: {
|
||||||
fields: {
|
fields: {
|
||||||
[field in string]: FieldAttribute;
|
[field in string]: DBFieldAttribute;
|
||||||
};
|
};
|
||||||
disableMigration?: boolean;
|
disableMigration?: boolean;
|
||||||
modelName?: string;
|
modelName?: string;
|
||||||
|
|||||||
@@ -6,5 +6,6 @@
|
|||||||
"lib": ["esnext", "dom", "dom.iterable"],
|
"lib": ["esnext", "dom", "dom.iterable"],
|
||||||
"types": ["node", "bun"]
|
"types": ["node", "bun"]
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "../core" }]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
getAuthTables,
|
getAuthTables,
|
||||||
type BetterAuthDbSchema,
|
type BetterAuthDBSchema,
|
||||||
type FieldAttribute,
|
type DBFieldAttribute,
|
||||||
} from "better-auth/db";
|
} from "better-auth/db";
|
||||||
import type { BetterAuthOptions } from "better-auth/types";
|
import type { BetterAuthOptions } from "better-auth/types";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
@@ -43,7 +43,7 @@ export const generateDrizzleSchema: SchemaGenerator = async ({
|
|||||||
const modelName = getModelName(table.modelName, adapter.options);
|
const modelName = getModelName(table.modelName, adapter.options);
|
||||||
const fields = table.fields;
|
const fields = table.fields;
|
||||||
|
|
||||||
function getType(name: string, field: FieldAttribute) {
|
function getType(name: string, field: DBFieldAttribute) {
|
||||||
// Not possible to reach, it's here to make typescript happy
|
// Not possible to reach, it's here to make typescript happy
|
||||||
if (!databaseType) {
|
if (!databaseType) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -224,7 +224,7 @@ function generateImport({
|
|||||||
options,
|
options,
|
||||||
}: {
|
}: {
|
||||||
databaseType: "sqlite" | "mysql" | "pg";
|
databaseType: "sqlite" | "mysql" | "pg";
|
||||||
tables: BetterAuthDbSchema;
|
tables: BetterAuthDBSchema;
|
||||||
options: BetterAuthOptions;
|
options: BetterAuthOptions;
|
||||||
}) {
|
}) {
|
||||||
const rootImports: string[] = [];
|
const rootImports: string[] = [];
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ export default defineBuildConfig({
|
|||||||
outDir: "dist",
|
outDir: "dist",
|
||||||
clean: true,
|
clean: true,
|
||||||
failOnWarn: false,
|
failOnWarn: false,
|
||||||
entries: ["./src/index.ts"],
|
entries: ["./src/index.ts", "./src/db/index.ts"],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,15 +12,28 @@
|
|||||||
"default": "./dist/index.mjs"
|
"default": "./dist/index.mjs"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"types": "./dist/index.d.cjs",
|
"types": "./dist/index.d.cts",
|
||||||
"default": "./dist/index.cjs"
|
"default": "./dist/index.cjs"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"./db": {
|
||||||
|
"import": {
|
||||||
|
"types": "./dist/db/index.d.ts",
|
||||||
|
"default": "./dist/db/index.mjs"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./dist/db/index.d.cts",
|
||||||
|
"default": "./dist/db/index.cjs"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
"index": [
|
"index": [
|
||||||
"dist/index.d.ts"
|
"dist/index.d.ts"
|
||||||
|
],
|
||||||
|
"db": [
|
||||||
|
"dist/db.d.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -31,5 +44,9 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"unbuild": "catalog:"
|
"unbuild": "catalog:"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"better-call": "catalog:",
|
||||||
|
"zod": "^4.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
packages/core/src/db/index.ts
Normal file
36
packages/core/src/db/index.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import type {
|
||||||
|
DBFieldAttribute,
|
||||||
|
DBFieldAttributeConfig,
|
||||||
|
DBFieldType,
|
||||||
|
DBPrimitive,
|
||||||
|
BetterAuthDBSchema,
|
||||||
|
} from "./type";
|
||||||
|
|
||||||
|
export type {
|
||||||
|
DBFieldAttribute,
|
||||||
|
DBFieldAttributeConfig,
|
||||||
|
DBFieldType,
|
||||||
|
DBPrimitive,
|
||||||
|
BetterAuthDBSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||||
|
*/
|
||||||
|
export type FieldAttribute = DBFieldAttribute;
|
||||||
|
/**
|
||||||
|
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||||
|
*/
|
||||||
|
export type FieldAttributeConfig = DBFieldAttributeConfig;
|
||||||
|
/**
|
||||||
|
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||||
|
*/
|
||||||
|
export type FieldType = DBFieldType;
|
||||||
|
/**
|
||||||
|
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||||
|
*/
|
||||||
|
export type Primitive = DBPrimitive;
|
||||||
|
/**
|
||||||
|
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||||
|
*/
|
||||||
|
export type BetterAuthDbSchema = BetterAuthDBSchema;
|
||||||
133
packages/core/src/db/type.ts
Normal file
133
packages/core/src/db/type.ts
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import type { ZodType } from "zod";
|
||||||
|
import type { LiteralString } from "../types";
|
||||||
|
|
||||||
|
export type DBFieldType =
|
||||||
|
| "string"
|
||||||
|
| "number"
|
||||||
|
| "boolean"
|
||||||
|
| "date"
|
||||||
|
| "json"
|
||||||
|
| `${"string" | "number"}[]`
|
||||||
|
| Array<LiteralString>;
|
||||||
|
|
||||||
|
export type DBPrimitive =
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Date
|
||||||
|
| null
|
||||||
|
| undefined
|
||||||
|
| string[]
|
||||||
|
| number[];
|
||||||
|
|
||||||
|
export type DBFieldAttributeConfig = {
|
||||||
|
/**
|
||||||
|
* If the field should be required on a new record.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
required?: boolean;
|
||||||
|
/**
|
||||||
|
* If the value should be returned on a response body.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
returned?: boolean;
|
||||||
|
/**
|
||||||
|
* If a value should be provided when creating a new record.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
input?: boolean;
|
||||||
|
/**
|
||||||
|
* Default value for the field
|
||||||
|
*
|
||||||
|
* Note: This will not create a default value on the database level. It will only
|
||||||
|
* be used when creating a new record.
|
||||||
|
*/
|
||||||
|
defaultValue?: DBPrimitive | (() => DBPrimitive);
|
||||||
|
/**
|
||||||
|
* Update value for the field
|
||||||
|
*
|
||||||
|
* Note: This will create an onUpdate trigger on the database level for supported adapters.
|
||||||
|
* It will be called when updating a record.
|
||||||
|
*/
|
||||||
|
onUpdate?: () => DBPrimitive;
|
||||||
|
/**
|
||||||
|
* transform the value before storing it.
|
||||||
|
*/
|
||||||
|
transform?: {
|
||||||
|
input?: (value: DBPrimitive) => DBPrimitive | Promise<DBPrimitive>;
|
||||||
|
output?: (value: DBPrimitive) => DBPrimitive | Promise<DBPrimitive>;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Reference to another model.
|
||||||
|
*/
|
||||||
|
references?: {
|
||||||
|
/**
|
||||||
|
* The model to reference.
|
||||||
|
*/
|
||||||
|
model: string;
|
||||||
|
/**
|
||||||
|
* The field on the referenced model.
|
||||||
|
*/
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* The action to perform when the reference is deleted.
|
||||||
|
* @default "cascade"
|
||||||
|
*/
|
||||||
|
onDelete?:
|
||||||
|
| "no action"
|
||||||
|
| "restrict"
|
||||||
|
| "cascade"
|
||||||
|
| "set null"
|
||||||
|
| "set default";
|
||||||
|
};
|
||||||
|
unique?: boolean;
|
||||||
|
/**
|
||||||
|
* If the field should be a bigint on the database instead of integer.
|
||||||
|
*/
|
||||||
|
bigint?: boolean;
|
||||||
|
/**
|
||||||
|
* A zod schema to validate the value.
|
||||||
|
*/
|
||||||
|
validator?: {
|
||||||
|
input?: ZodType;
|
||||||
|
output?: ZodType;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The name of the field on the database.
|
||||||
|
*/
|
||||||
|
fieldName?: string;
|
||||||
|
/**
|
||||||
|
* If the field should be sortable.
|
||||||
|
*
|
||||||
|
* applicable only for `text` type.
|
||||||
|
* It's useful to mark fields varchar instead of text.
|
||||||
|
*/
|
||||||
|
sortable?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DBFieldAttribute<T extends DBFieldType = DBFieldType> = {
|
||||||
|
type: T;
|
||||||
|
} & DBFieldAttributeConfig;
|
||||||
|
|
||||||
|
export type BetterAuthDBSchema = Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name of the table in the database
|
||||||
|
*/
|
||||||
|
modelName: string;
|
||||||
|
/**
|
||||||
|
* The fields of the table
|
||||||
|
*/
|
||||||
|
fields: Record<string, DBFieldAttribute>;
|
||||||
|
/**
|
||||||
|
* Whether to disable migrations for this table
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
disableMigrations?: boolean;
|
||||||
|
/**
|
||||||
|
* The order of the table
|
||||||
|
*/
|
||||||
|
order?: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
1
packages/core/src/types/helper.ts
Normal file
1
packages/core/src/types/helper.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type LiteralString = "" | (string & Record<never, never>);
|
||||||
1
packages/core/src/types/index.ts
Normal file
1
packages/core/src/types/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./helper";
|
||||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -906,6 +906,13 @@ importers:
|
|||||||
version: 3.6.1(sass@1.90.0)(typescript@5.9.2)(vue@3.5.19(typescript@5.9.2))
|
version: 3.6.1(sass@1.90.0)(typescript@5.9.2)(vue@3.5.19(typescript@5.9.2))
|
||||||
|
|
||||||
packages/core:
|
packages/core:
|
||||||
|
dependencies:
|
||||||
|
better-call:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 1.0.19
|
||||||
|
zod:
|
||||||
|
specifier: ^4.1.5
|
||||||
|
version: 4.1.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
unbuild:
|
unbuild:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
@@ -16013,7 +16020,9 @@ snapshots:
|
|||||||
metro-runtime: 0.83.1
|
metro-runtime: 0.83.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
|
- bufferutil
|
||||||
- supports-color
|
- supports-color
|
||||||
|
- utf-8-validate
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@react-native/normalize-colors@0.79.6': {}
|
'@react-native/normalize-colors@0.79.6': {}
|
||||||
|
|||||||
Reference in New Issue
Block a user