UNPKG

@convex-dev/better-auth

Version:
114 lines (110 loc) 4.78 kB
// Manually add fields to index on for schema generation, // all fields in the schema specialFields are automatically indexed export const indexFields = { account: ["accountId", ["accountId", "providerId"], ["providerId", "userId"]], rateLimit: ["key"], session: ["expiresAt", ["expiresAt", "userId"]], verification: ["expiresAt", "identifier"], user: [["email", "name"], "name", "userId"], passkey: ["credentialID"], oauthConsent: [["clientId", "userId"]], }; // Return map of unique, sortable, and reference fields const specialFields = (tables) => Object.fromEntries(Object.entries(tables) .map(([key, table]) => { const fields = Object.fromEntries(Object.entries(table.fields) .map(([fieldKey, field]) => [ field.fieldName ?? fieldKey, { ...(field.sortable ? { sortable: true } : {}), ...(field.unique ? { unique: true } : {}), ...(field.references ? { references: field.references } : {}), }, ]) .filter(([_key, value]) => typeof value === "object" ? Object.keys(value).length > 0 : true)); return [key, fields]; }) .filter(([_key, value]) => typeof value === "object" ? Object.keys(value).length > 0 : true)); const mergedIndexFields = (tables) => Object.fromEntries(Object.entries(tables).map(([key, table]) => { const manualIndexes = indexFields[key]?.map((index) => { return typeof index === "string" ? (table.fields[index]?.fieldName ?? index) : index.map((i) => table.fields[i]?.fieldName ?? i); }) || []; const specialFieldIndexes = Object.keys(specialFields(tables)[key] || {}).filter((index) => !manualIndexes.some((m) => Array.isArray(m) ? m[0] === index : m === index)); return [key, manualIndexes.concat(specialFieldIndexes)]; })); export const createSchema = async ({ file, tables, }) => { // stop convex esbuild from throwing over this import, only runs // in the better auth cli const pathImport = "path"; const path = await import(pathImport); const baseName = path.basename(path.resolve(process.cwd(), file ?? "")); // if the target directory is named "convex", they're almost definitely // generating the schema in the wrong directory, likely would replace the // app schema if (baseName === "convex") { throw new Error("Better Auth schema must be generated in the Better Auth component directory."); } let code = `/** * This file is auto-generated. Do not edit this file manually. * To regenerate the schema, run: * \`npx @better-auth/cli generate --output ${file} -y\` * * To customize the schema, generate to an alternate file and import * the table definitions to your schema file. See * https://labs.convex.dev/better-auth/features/local-install#adding-custom-indexes. */ import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export const tables = { `; for (const tableKey in tables) { const table = tables[tableKey]; const modelName = table.modelName; // No id fields in Convex schema const fields = Object.fromEntries(Object.entries(table.fields).filter(([key]) => key !== "id")); function getType(name, field) { const type = field.type; const typeMap = { string: `v.string()`, boolean: `v.boolean()`, number: `v.number()`, date: `v.number()`, json: `v.string()`, "number[]": `v.array(v.number())`, "string[]": `v.array(v.string())`, }; return typeMap[type]; } const indexes = mergedIndexFields(tables)[tableKey]?.map((index) => { const indexArray = Array.isArray(index) ? index.sort() : [index]; const indexName = indexArray.join("_"); return `.index("${indexName}", ${JSON.stringify(indexArray)})`; }) || []; const schema = `${modelName}: defineTable({ ${Object.keys(fields) .map((field) => { const attr = fields[field]; const type = getType(field, attr); const optional = (fieldSchema) => attr.required ? fieldSchema : `v.optional(v.union(v.null(), ${fieldSchema}))`; return ` ${attr.fieldName ?? field}: ${optional(type)},`; }) .join("\n")} })${indexes.length > 0 ? `\n ${indexes.join("\n ")}` : ""},\n`; code += ` ${schema}`; } code += `}; const schema = defineSchema(tables); export default schema; `; return { code, path: file ?? "./schema.ts", overwrite: true, }; }; //# sourceMappingURL=create-schema.js.map