mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Implement comprehensive auth template system
This commit is contained in:
@@ -18,13 +18,14 @@ export async function setupAuth(
|
|||||||
projectDir: string,
|
projectDir: string,
|
||||||
enableAuth: boolean,
|
enableAuth: boolean,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
if (!enableAuth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const serverDir = path.join(projectDir, "packages/server");
|
const serverDir = path.join(projectDir, "packages/server");
|
||||||
const clientDir = path.join(projectDir, "packages/client");
|
const clientDir = path.join(projectDir, "packages/client");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!enableAuth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
addPackageDependency({
|
addPackageDependency({
|
||||||
dependencies: ["better-auth"],
|
dependencies: ["better-auth"],
|
||||||
projectDir: serverDir,
|
projectDir: serverDir,
|
||||||
|
|||||||
@@ -40,6 +40,65 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
|||||||
|
|
||||||
if (await fs.pathExists(ormTemplateDir)) {
|
if (await fs.pathExists(ormTemplateDir)) {
|
||||||
await fs.copy(ormTemplateDir, projectDir, { overwrite: true });
|
await fs.copy(ormTemplateDir, projectDir, { overwrite: true });
|
||||||
|
|
||||||
|
const serverSrcPath = path.join(projectDir, "packages/server/src");
|
||||||
|
const baseLibPath = path.join(serverSrcPath, "lib");
|
||||||
|
const withAuthLibPath = path.join(serverSrcPath, "with-auth-lib");
|
||||||
|
|
||||||
|
if (options.auth) {
|
||||||
|
await fs.remove(baseLibPath);
|
||||||
|
await fs.move(withAuthLibPath, baseLibPath);
|
||||||
|
|
||||||
|
if (options.orm === "prisma") {
|
||||||
|
const schemaPath = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/prisma/schema.prisma",
|
||||||
|
);
|
||||||
|
const withAuthSchemaPath = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/prisma/with-auth-schema.prisma",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (await fs.pathExists(withAuthSchemaPath)) {
|
||||||
|
await fs.remove(schemaPath);
|
||||||
|
await fs.move(withAuthSchemaPath, schemaPath);
|
||||||
|
}
|
||||||
|
} else if (options.orm === "drizzle") {
|
||||||
|
const schemaPath = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/src/db/schema.ts",
|
||||||
|
);
|
||||||
|
const withAuthSchemaPath = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/src/db/with-auth-schema.ts",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (await fs.pathExists(withAuthSchemaPath)) {
|
||||||
|
await fs.remove(schemaPath);
|
||||||
|
await fs.move(withAuthSchemaPath, schemaPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await fs.remove(withAuthLibPath);
|
||||||
|
|
||||||
|
if (options.orm === "prisma") {
|
||||||
|
const withAuthSchema = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/prisma/with-auth-schema.prisma",
|
||||||
|
);
|
||||||
|
if (await fs.pathExists(withAuthSchema)) {
|
||||||
|
await fs.remove(withAuthSchema);
|
||||||
|
}
|
||||||
|
} else if (options.orm === "drizzle") {
|
||||||
|
const withAuthSchema = path.join(
|
||||||
|
projectDir,
|
||||||
|
"packages/server/src/db/with-auth-schema.ts",
|
||||||
|
);
|
||||||
|
if (await fs.pathExists(withAuthSchema)) {
|
||||||
|
await fs.remove(withAuthSchema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +110,6 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await setupAuth(projectDir, options.auth);
|
await setupAuth(projectDir, options.auth);
|
||||||
|
|
||||||
await setupEnvironmentVariables(projectDir, options);
|
await setupEnvironmentVariables(projectDir, options);
|
||||||
|
|
||||||
if (options.git) {
|
if (options.git) {
|
||||||
@@ -63,7 +121,6 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await updatePackageConfigurations(projectDir, options);
|
await updatePackageConfigurations(projectDir, options);
|
||||||
|
|
||||||
await createReadme(projectDir, options);
|
await createReadme(projectDir, options);
|
||||||
|
|
||||||
displayPostInstallInstructions(
|
displayPostInstallInstructions(
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ export async function setupEnvironmentVariables(
|
|||||||
envContent = await fs.readFile(envPath, "utf8");
|
envContent = await fs.readFile(envPath, "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!envContent.includes("CORS_ORIGIN")) {
|
||||||
|
envContent += "\nCORS_ORIGIN=http://localhost:3001";
|
||||||
|
}
|
||||||
|
|
||||||
if (options.auth) {
|
if (options.auth) {
|
||||||
if (!envContent.includes("BETTER_AUTH_SECRET")) {
|
if (!envContent.includes("BETTER_AUTH_SECRET")) {
|
||||||
envContent += `\nBETTER_AUTH_SECRET=${generateAuthSecret()}`;
|
envContent += `\nBETTER_AUTH_SECRET=${generateAuthSecret()}`;
|
||||||
@@ -25,16 +29,6 @@ export async function setupEnvironmentVariables(
|
|||||||
if (!envContent.includes("BETTER_AUTH_URL")) {
|
if (!envContent.includes("BETTER_AUTH_URL")) {
|
||||||
envContent += "\nBETTER_AUTH_URL=http://localhost:3000";
|
envContent += "\nBETTER_AUTH_URL=http://localhost:3000";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!envContent.includes("CORS_ORIGIN")) {
|
|
||||||
envContent += "\nCORS_ORIGIN=http://localhost:3001";
|
|
||||||
}
|
|
||||||
|
|
||||||
const clientEnvPath = path.join(clientDir, ".env");
|
|
||||||
if (!(await fs.pathExists(clientEnvPath))) {
|
|
||||||
const clientEnvContent = "VITE_SERVER_URL=http://localhost:3000\n";
|
|
||||||
await fs.writeFile(clientEnvPath, clientEnvContent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.database !== "none") {
|
if (options.database !== "none") {
|
||||||
@@ -54,4 +48,17 @@ export async function setupEnvironmentVariables(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(envPath, envContent.trim());
|
await fs.writeFile(envPath, envContent.trim());
|
||||||
|
|
||||||
|
const clientEnvPath = path.join(clientDir, ".env");
|
||||||
|
let clientEnvContent = "";
|
||||||
|
|
||||||
|
if (await fs.pathExists(clientEnvPath)) {
|
||||||
|
clientEnvContent = await fs.readFile(clientEnvPath, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clientEnvContent.includes("VITE_SERVER_URL")) {
|
||||||
|
clientEnvContent += "VITE_SERVER_URL=http://localhost:3000\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(clientEnvPath, clientEnvContent.trim());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,32 +33,30 @@ function getDatabaseInstructions(
|
|||||||
const instructions = [];
|
const instructions = [];
|
||||||
|
|
||||||
if (orm === "prisma") {
|
if (orm === "prisma") {
|
||||||
instructions.push(
|
|
||||||
`${pc.cyan("•")} Apply schema: ${pc.dim(`${runCmd} db:push`)}`,
|
|
||||||
);
|
|
||||||
instructions.push(
|
|
||||||
`${pc.cyan("•")} Database UI: ${pc.dim(`${runCmd} db:studio`)}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (database === "sqlite") {
|
if (database === "sqlite") {
|
||||||
instructions.push(
|
instructions.push(
|
||||||
`${pc.yellow("NOTE:")} Turso support with Prisma is in Early Access and requires additional setup.`,
|
`${pc.yellow("NOTE:")} Turso support with Prisma is in Early Access and requires additional setup.`,
|
||||||
`${pc.dim("Learn more at: https://www.prisma.io/docs/orm/overview/databases/turso")}`,
|
`${pc.dim("Learn more at: https://www.prisma.io/docs/orm/overview/databases/turso")}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (orm === "drizzle") {
|
|
||||||
instructions.push(
|
instructions.push(
|
||||||
`${pc.cyan("•")} Apply schema: ${pc.dim(`${runCmd} db:push`)}`,
|
`${pc.cyan("•")} Apply schema: ${pc.dim(`${runCmd} db:push`)}`,
|
||||||
);
|
);
|
||||||
instructions.push(
|
instructions.push(
|
||||||
`${pc.cyan("•")} Database UI: ${pc.dim(`${runCmd} db:studio`)}`,
|
`${pc.cyan("•")} Database UI: ${pc.dim(`${runCmd} db:studio`)}`,
|
||||||
);
|
);
|
||||||
|
} else if (orm === "drizzle") {
|
||||||
if (database === "sqlite") {
|
if (database === "sqlite") {
|
||||||
instructions.push(
|
instructions.push(
|
||||||
`${pc.cyan("•")} Start local DB: ${pc.dim(`cd packages/server && ${runCmd} db:local`)}`,
|
`${pc.cyan("•")} Start local DB: ${pc.dim(`cd packages/server && ${runCmd} db:local`)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
instructions.push(
|
||||||
|
`${pc.cyan("•")} Apply schema: ${pc.dim(`${runCmd} db:push`)}`,
|
||||||
|
);
|
||||||
|
instructions.push(
|
||||||
|
`${pc.cyan("•")} Database UI: ${pc.dim(`${runCmd} db:studio`)}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return instructions.length
|
return instructions.length
|
||||||
|
|||||||
@@ -31,12 +31,6 @@ const trpcClient = trpc.createClient({
|
|||||||
links: [
|
links: [
|
||||||
httpBatchLink({
|
httpBatchLink({
|
||||||
url: `${import.meta.env.VITE_SERVER_URL}/trpc`,
|
url: `${import.meta.env.VITE_SERVER_URL}/trpc`,
|
||||||
fetch(url, options) {
|
|
||||||
return fetch(url, {
|
|
||||||
...options,
|
|
||||||
credentials: "include",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
77
apps/cli/template/with-auth/packages/client/src/main.tsx
Normal file
77
apps/cli/template/with-auth/packages/client/src/main.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import {
|
||||||
|
QueryCache,
|
||||||
|
QueryClient,
|
||||||
|
QueryClientProvider,
|
||||||
|
} from "@tanstack/react-query";
|
||||||
|
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
||||||
|
import { httpBatchLink } from "@trpc/client";
|
||||||
|
import { createTRPCQueryUtils } from "@trpc/react-query";
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import Loader from "./components/loader";
|
||||||
|
import { routeTree } from "./routeTree.gen";
|
||||||
|
import { trpc } from "./utils/trpc";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
queryCache: new QueryCache({
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message, {
|
||||||
|
action: {
|
||||||
|
label: "retry",
|
||||||
|
onClick: () => {
|
||||||
|
queryClient.invalidateQueries();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const trpcClient = trpc.createClient({
|
||||||
|
links: [
|
||||||
|
httpBatchLink({
|
||||||
|
url: `${import.meta.env.VITE_SERVER_URL}/trpc`,
|
||||||
|
fetch(url, options) {
|
||||||
|
return fetch(url, {
|
||||||
|
...options,
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const trpcQueryUtils = createTRPCQueryUtils({
|
||||||
|
queryClient,
|
||||||
|
client: trpcClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
routeTree,
|
||||||
|
defaultPreload: "intent",
|
||||||
|
context: { trpcQueryUtils },
|
||||||
|
defaultPendingComponent: () => <Loader />,
|
||||||
|
Wrap: function WrapComponent({ children }) {
|
||||||
|
return (
|
||||||
|
<trpc.Provider client={trpcClient} queryClient={queryClient}>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
{children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
</trpc.Provider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register things for typesafety
|
||||||
|
declare module "@tanstack/react-router" {
|
||||||
|
interface Register {
|
||||||
|
router: typeof router;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootElement = document.getElementById("app")!;
|
||||||
|
|
||||||
|
if (!rootElement.innerHTML) {
|
||||||
|
const root = ReactDOM.createRoot(rootElement);
|
||||||
|
root.render(<RouterProvider router={router} />);
|
||||||
|
}
|
||||||
@@ -1,47 +1,7 @@
|
|||||||
import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core";
|
import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const user = pgTable("user", {
|
export const todo = pgTable("todo", {
|
||||||
id: text("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
name: text('name').notNull(),
|
text: text("text").notNull(),
|
||||||
email: text('email').notNull().unique(),
|
completed: boolean("completed").default(false).notNull()
|
||||||
emailVerified: boolean('email_verified').notNull(),
|
});
|
||||||
image: text('image'),
|
|
||||||
createdAt: timestamp('created_at').notNull(),
|
|
||||||
updatedAt: timestamp('updated_at').notNull()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const session = pgTable("session", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
expiresAt: timestamp('expires_at').notNull(),
|
|
||||||
token: text('token').notNull().unique(),
|
|
||||||
createdAt: timestamp('created_at').notNull(),
|
|
||||||
updatedAt: timestamp('updated_at').notNull(),
|
|
||||||
ipAddress: text('ip_address'),
|
|
||||||
userAgent: text('user_agent'),
|
|
||||||
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' })
|
|
||||||
});
|
|
||||||
|
|
||||||
export const account = pgTable("account", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
accountId: text('account_id').notNull(),
|
|
||||||
providerId: text('provider_id').notNull(),
|
|
||||||
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' }),
|
|
||||||
accessToken: text('access_token'),
|
|
||||||
refreshToken: text('refresh_token'),
|
|
||||||
idToken: text('id_token'),
|
|
||||||
accessTokenExpiresAt: timestamp('access_token_expires_at'),
|
|
||||||
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
|
|
||||||
scope: text('scope'),
|
|
||||||
password: text('password'),
|
|
||||||
createdAt: timestamp('created_at').notNull(),
|
|
||||||
updatedAt: timestamp('updated_at').notNull()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const verification = pgTable("verification", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
identifier: text('identifier').notNull(),
|
|
||||||
value: text('value').notNull(),
|
|
||||||
expiresAt: timestamp('expires_at').notNull(),
|
|
||||||
createdAt: timestamp('created_at'),
|
|
||||||
updatedAt: timestamp('updated_at')
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const todo = pgTable("todo", {
|
||||||
|
id: serial("id").primaryKey(),
|
||||||
|
text: text("text").notNull(),
|
||||||
|
completed: boolean("completed").default(false).notNull()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const user = pgTable("user", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
name: text('name').notNull(),
|
||||||
|
email: text('email').notNull().unique(),
|
||||||
|
emailVerified: boolean('email_verified').notNull(),
|
||||||
|
image: text('image'),
|
||||||
|
createdAt: timestamp('created_at').notNull(),
|
||||||
|
updatedAt: timestamp('updated_at').notNull()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const session = pgTable("session", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
expiresAt: timestamp('expires_at').notNull(),
|
||||||
|
token: text('token').notNull().unique(),
|
||||||
|
createdAt: timestamp('created_at').notNull(),
|
||||||
|
updatedAt: timestamp('updated_at').notNull(),
|
||||||
|
ipAddress: text('ip_address'),
|
||||||
|
userAgent: text('user_agent'),
|
||||||
|
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' })
|
||||||
|
});
|
||||||
|
|
||||||
|
export const account = pgTable("account", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
accountId: text('account_id').notNull(),
|
||||||
|
providerId: text('provider_id').notNull(),
|
||||||
|
userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' }),
|
||||||
|
accessToken: text('access_token'),
|
||||||
|
refreshToken: text('refresh_token'),
|
||||||
|
idToken: text('id_token'),
|
||||||
|
accessTokenExpiresAt: timestamp('access_token_expires_at'),
|
||||||
|
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
|
||||||
|
scope: text('scope'),
|
||||||
|
password: text('password'),
|
||||||
|
createdAt: timestamp('created_at').notNull(),
|
||||||
|
updatedAt: timestamp('updated_at').notNull()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const verification = pgTable("verification", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
identifier: text('identifier').notNull(),
|
||||||
|
value: text('value').notNull(),
|
||||||
|
expiresAt: timestamp('expires_at').notNull(),
|
||||||
|
createdAt: timestamp('created_at'),
|
||||||
|
updatedAt: timestamp('updated_at')
|
||||||
|
});
|
||||||
@@ -5,7 +5,7 @@ import * as schema from "../db/schema";
|
|||||||
|
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
database: drizzleAdapter(db, {
|
database: drizzleAdapter(db, {
|
||||||
provider: "sqlite",
|
provider: "pg",
|
||||||
schema: schema,
|
schema: schema,
|
||||||
}),
|
}),
|
||||||
trustedOrigins: [process.env.CORS_ORIGIN!],
|
trustedOrigins: [process.env.CORS_ORIGIN!],
|
||||||
@@ -1,55 +1,7 @@
|
|||||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
export const user = sqliteTable("user", {
|
export const todo = sqliteTable("todo", {
|
||||||
id: text("id").primaryKey(),
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
name: text("name").notNull(),
|
text: text("text").notNull(),
|
||||||
email: text("email").notNull().unique(),
|
completed: integer("completed", { mode: "boolean" }).default(false).notNull()
|
||||||
emailVerified: integer("email_verified", { mode: "boolean" }).notNull(),
|
|
||||||
image: text("image"),
|
|
||||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
||||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const session = sqliteTable("session", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
|
||||||
token: text("token").notNull().unique(),
|
|
||||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
||||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
||||||
ipAddress: text("ip_address"),
|
|
||||||
userAgent: text("user_agent"),
|
|
||||||
userId: text("user_id")
|
|
||||||
.notNull()
|
|
||||||
.references(() => user.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const account = sqliteTable("account", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
accountId: text("account_id").notNull(),
|
|
||||||
providerId: text("provider_id").notNull(),
|
|
||||||
userId: text("user_id")
|
|
||||||
.notNull()
|
|
||||||
.references(() => user.id),
|
|
||||||
accessToken: text("access_token"),
|
|
||||||
refreshToken: text("refresh_token"),
|
|
||||||
idToken: text("id_token"),
|
|
||||||
accessTokenExpiresAt: integer("access_token_expires_at", {
|
|
||||||
mode: "timestamp",
|
|
||||||
}),
|
|
||||||
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
|
||||||
mode: "timestamp",
|
|
||||||
}),
|
|
||||||
scope: text("scope"),
|
|
||||||
password: text("password"),
|
|
||||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
|
||||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const verification = sqliteTable("verification", {
|
|
||||||
id: text("id").primaryKey(),
|
|
||||||
identifier: text("identifier").notNull(),
|
|
||||||
value: text("value").notNull(),
|
|
||||||
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
|
||||||
createdAt: integer("created_at", { mode: "timestamp" }),
|
|
||||||
updatedAt: integer("updated_at", { mode: "timestamp" }),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
|
export const todo = sqliteTable("todo", {
|
||||||
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
text: text("text").notNull(),
|
||||||
|
completed: integer("completed", { mode: "boolean" }).default(false).notNull()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const user = sqliteTable("user", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
email: text("email").notNull().unique(),
|
||||||
|
emailVerified: integer("email_verified", { mode: "boolean" }).notNull(),
|
||||||
|
image: text("image"),
|
||||||
|
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
||||||
|
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const session = sqliteTable("session", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||||
|
token: text("token").notNull().unique(),
|
||||||
|
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
||||||
|
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
||||||
|
ipAddress: text("ip_address"),
|
||||||
|
userAgent: text("user_agent"),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const account = sqliteTable("account", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
accountId: text("account_id").notNull(),
|
||||||
|
providerId: text("provider_id").notNull(),
|
||||||
|
userId: text("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id),
|
||||||
|
accessToken: text("access_token"),
|
||||||
|
refreshToken: text("refresh_token"),
|
||||||
|
idToken: text("id_token"),
|
||||||
|
accessTokenExpiresAt: integer("access_token_expires_at", {
|
||||||
|
mode: "timestamp",
|
||||||
|
}),
|
||||||
|
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
||||||
|
mode: "timestamp",
|
||||||
|
}),
|
||||||
|
scope: text("scope"),
|
||||||
|
password: text("password"),
|
||||||
|
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
||||||
|
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const verification = sqliteTable("verification", {
|
||||||
|
id: text("id").primaryKey(),
|
||||||
|
identifier: text("identifier").notNull(),
|
||||||
|
value: text("value").notNull(),
|
||||||
|
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
|
||||||
|
createdAt: integer("created_at", { mode: "timestamp" }),
|
||||||
|
updatedAt: integer("updated_at", { mode: "timestamp" }),
|
||||||
|
});
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
||||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
@@ -13,6 +7,14 @@ datasource db {
|
|||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Todo {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
text String
|
||||||
|
completed Boolean @default(false)
|
||||||
|
|
||||||
|
@@map("todo")
|
||||||
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @map("_id")
|
id String @id @map("_id")
|
||||||
name String
|
name String
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgres"
|
||||||
|
url = env("DATABASE_URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Todo {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
text String
|
||||||
|
completed Boolean @default(false)
|
||||||
|
|
||||||
|
@@map("todo")
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @map("_id")
|
||||||
|
name String
|
||||||
|
email String
|
||||||
|
emailVerified Boolean
|
||||||
|
image String?
|
||||||
|
createdAt DateTime
|
||||||
|
updatedAt DateTime
|
||||||
|
sessions Session[]
|
||||||
|
accounts Account[]
|
||||||
|
|
||||||
|
@@unique([email])
|
||||||
|
@@map("user")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @map("_id")
|
||||||
|
expiresAt DateTime
|
||||||
|
token String
|
||||||
|
createdAt DateTime
|
||||||
|
updatedAt DateTime
|
||||||
|
ipAddress String?
|
||||||
|
userAgent String?
|
||||||
|
userId String
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@unique([token])
|
||||||
|
@@map("session")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Account {
|
||||||
|
id String @id @map("_id")
|
||||||
|
accountId String
|
||||||
|
providerId String
|
||||||
|
userId String
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
accessToken String?
|
||||||
|
refreshToken String?
|
||||||
|
idToken String?
|
||||||
|
accessTokenExpiresAt DateTime?
|
||||||
|
refreshTokenExpiresAt DateTime?
|
||||||
|
scope String?
|
||||||
|
password String?
|
||||||
|
createdAt DateTime
|
||||||
|
updatedAt DateTime
|
||||||
|
|
||||||
|
@@map("account")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Verification {
|
||||||
|
id String @id @map("_id")
|
||||||
|
identifier String
|
||||||
|
value String
|
||||||
|
expiresAt DateTime
|
||||||
|
createdAt DateTime?
|
||||||
|
updatedAt DateTime?
|
||||||
|
|
||||||
|
@@map("verification")
|
||||||
|
}
|
||||||
@@ -1,74 +1,16 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
||||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "sqlite"
|
||||||
url = "file:./dev.db"
|
url = "file:./local.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model Todo {
|
||||||
id String @id @map("_id")
|
id Int @id @default(autoincrement())
|
||||||
name String
|
text String
|
||||||
email String
|
completed Boolean @default(false)
|
||||||
emailVerified Boolean
|
|
||||||
image String?
|
|
||||||
createdAt DateTime
|
|
||||||
updatedAt DateTime
|
|
||||||
sessions Session[]
|
|
||||||
accounts Account[]
|
|
||||||
|
|
||||||
@@unique([email])
|
@@map("todo")
|
||||||
@@map("user")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Session {
|
|
||||||
id String @id @map("_id")
|
|
||||||
expiresAt DateTime
|
|
||||||
token String
|
|
||||||
createdAt DateTime
|
|
||||||
updatedAt DateTime
|
|
||||||
ipAddress String?
|
|
||||||
userAgent String?
|
|
||||||
userId String
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
@@unique([token])
|
|
||||||
@@map("session")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Account {
|
|
||||||
id String @id @map("_id")
|
|
||||||
accountId String
|
|
||||||
providerId String
|
|
||||||
userId String
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
accessToken String?
|
|
||||||
refreshToken String?
|
|
||||||
idToken String?
|
|
||||||
accessTokenExpiresAt DateTime?
|
|
||||||
refreshTokenExpiresAt DateTime?
|
|
||||||
scope String?
|
|
||||||
password String?
|
|
||||||
createdAt DateTime
|
|
||||||
updatedAt DateTime
|
|
||||||
|
|
||||||
@@map("account")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Verification {
|
|
||||||
id String @id @map("_id")
|
|
||||||
identifier String
|
|
||||||
value String
|
|
||||||
expiresAt DateTime
|
|
||||||
createdAt DateTime?
|
|
||||||
updatedAt DateTime?
|
|
||||||
|
|
||||||
@@map("verification")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
url = "file:./local.db"
|
||||||
|
}
|
||||||
|
|
||||||
|
model Todo {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
text String
|
||||||
|
completed Boolean @default(false)
|
||||||
|
|
||||||
|
@@map("todo")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user