authverse 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/index.cjs +827 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +799 -0
- package/dist/template/api/route.ts +4 -0
- package/dist/template/app-auth-uiDesign/forget/page.tsx +7 -0
- package/dist/template/app-auth-uiDesign/layout.tsx +9 -0
- package/dist/template/app-auth-uiDesign/login/page.tsx +7 -0
- package/dist/template/app-auth-uiDesign/reset-password/page.tsx +7 -0
- package/dist/template/app-auth-uiDesign/signup/page.tsx +7 -0
- package/dist/template/components/ForgetComponent.tsx +121 -0
- package/dist/template/components/GithubProviders.tsx +21 -0
- package/dist/template/components/GoogleProviders.tsx +21 -0
- package/dist/template/components/LoginComponent.tsx +145 -0
- package/dist/template/components/Logout.tsx +21 -0
- package/dist/template/components/ResetComponent.tsx +150 -0
- package/dist/template/components/SingUpComponent.tsx +173 -0
- package/dist/template/config/drizzle.config.ts +13 -0
- package/dist/template/config/prisma.config.ts +12 -0
- package/dist/template/db/drizzle.ts +6 -0
- package/dist/template/db/schema.ts +68 -0
- package/dist/template/email/reset-password.tsx +132 -0
- package/dist/template/lib/Mongodb/auth.ts +20 -0
- package/dist/template/lib/Mysql/auth.ts +27 -0
- package/dist/template/lib/Postgresql/auth.ts +20 -0
- package/dist/template/lib/auth-client.ts +5 -0
- package/dist/template/lib/auth-drizzle.ts +16 -0
- package/dist/template/prisma/mongodb/schema.prisma +70 -0
- package/dist/template/prisma/mysql/schema.prisma +68 -0
- package/dist/template/prisma/postgresql/schema.prisma +68 -0
- package/dist/template/proxy/proxy.ts +15 -0
- package/dist/template/server/user.ts +49 -0
- package/package.json +62 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// cli/init.ts
|
|
7
|
+
import inquirer from "inquirer";
|
|
8
|
+
|
|
9
|
+
// script/prisma.ts
|
|
10
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11
|
+
import path2 from "path";
|
|
12
|
+
import fs2 from "fs";
|
|
13
|
+
import chalk2 from "chalk";
|
|
14
|
+
import { execSync as execSync2 } from "child_process";
|
|
15
|
+
|
|
16
|
+
// function/GenerateSecret.ts
|
|
17
|
+
import crypto from "crypto";
|
|
18
|
+
var GenerateSecret = async () => {
|
|
19
|
+
const secret = crypto.randomBytes(64).toString("hex");
|
|
20
|
+
return secret;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// script/authUi.ts
|
|
24
|
+
import chalk from "chalk";
|
|
25
|
+
import { execSync } from "child_process";
|
|
26
|
+
import path from "path";
|
|
27
|
+
import fs from "fs";
|
|
28
|
+
import { fileURLToPath } from "url";
|
|
29
|
+
var authUiRun = async ({ folder }) => {
|
|
30
|
+
try {
|
|
31
|
+
console.log(chalk.yellow("\n Updating AuthUi Files\n"));
|
|
32
|
+
execSync("npx shadcn@latest add button sonner card field input", {
|
|
33
|
+
stdio: "inherit"
|
|
34
|
+
});
|
|
35
|
+
execSync("npm install react-hook-form @hookform/resolvers", {
|
|
36
|
+
stdio: "inherit"
|
|
37
|
+
});
|
|
38
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
39
|
+
const __dirname = path.dirname(__filename);
|
|
40
|
+
const projectDir = process.cwd();
|
|
41
|
+
const componentPath = path.resolve(__dirname, "./template/components");
|
|
42
|
+
const destinationPath = path.join(
|
|
43
|
+
projectDir,
|
|
44
|
+
folder,
|
|
45
|
+
"components",
|
|
46
|
+
"authverse"
|
|
47
|
+
);
|
|
48
|
+
if (!fs.existsSync(destinationPath)) {
|
|
49
|
+
fs.mkdirSync(destinationPath, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
const LoginDestinationPath = path.join(
|
|
52
|
+
destinationPath,
|
|
53
|
+
"LoginComponent.tsx"
|
|
54
|
+
);
|
|
55
|
+
fs.copyFileSync(
|
|
56
|
+
`${componentPath}/LoginComponent.tsx`,
|
|
57
|
+
LoginDestinationPath
|
|
58
|
+
);
|
|
59
|
+
const SignUpDestinationPath = path.join(
|
|
60
|
+
destinationPath,
|
|
61
|
+
"SingUpComponent.tsx"
|
|
62
|
+
);
|
|
63
|
+
fs.copyFileSync(
|
|
64
|
+
`${componentPath}/SingUpComponent.tsx`,
|
|
65
|
+
SignUpDestinationPath
|
|
66
|
+
);
|
|
67
|
+
const LogoutDestinationPath = path.join(destinationPath, "Logout.tsx");
|
|
68
|
+
fs.copyFileSync(`${componentPath}/Logout.tsx`, LogoutDestinationPath);
|
|
69
|
+
const authTemplatePath = path.resolve(
|
|
70
|
+
__dirname,
|
|
71
|
+
"./template/app-auth-uiDesign"
|
|
72
|
+
);
|
|
73
|
+
const appDestinationPath = path.join(projectDir, folder, "app", "auth");
|
|
74
|
+
if (!fs.existsSync(appDestinationPath)) {
|
|
75
|
+
fs.mkdirSync(appDestinationPath, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
const layoutDestinationPath = path.join(appDestinationPath, "layout.tsx");
|
|
78
|
+
fs.copyFileSync(`${authTemplatePath}/layout.tsx`, layoutDestinationPath);
|
|
79
|
+
const loginDestinationDir = path.join(appDestinationPath, "login");
|
|
80
|
+
if (!fs.existsSync(loginDestinationDir)) {
|
|
81
|
+
fs.mkdirSync(loginDestinationDir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
const loginPageDestinationPath = path.join(loginDestinationDir, "page.tsx");
|
|
84
|
+
fs.copyFileSync(
|
|
85
|
+
`${authTemplatePath}/login/page.tsx`,
|
|
86
|
+
loginPageDestinationPath
|
|
87
|
+
);
|
|
88
|
+
const signUpDestinationDir = path.join(appDestinationPath, "signup");
|
|
89
|
+
if (!fs.existsSync(signUpDestinationDir)) {
|
|
90
|
+
fs.mkdirSync(signUpDestinationDir, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
const signUpPageDestinationPath = path.join(
|
|
93
|
+
signUpDestinationDir,
|
|
94
|
+
"page.tsx"
|
|
95
|
+
);
|
|
96
|
+
fs.copyFileSync(
|
|
97
|
+
`${authTemplatePath}/signup/page.tsx`,
|
|
98
|
+
signUpPageDestinationPath
|
|
99
|
+
);
|
|
100
|
+
const layoutPath = path.join(projectDir, folder, "app", "layout.tsx");
|
|
101
|
+
if (fs.existsSync(layoutPath)) {
|
|
102
|
+
let layoutContent = fs.readFileSync(layoutPath, "utf-8");
|
|
103
|
+
if (!layoutContent.includes("Toaster")) {
|
|
104
|
+
layoutContent = `import { Toaster } from "@/components/ui/sonner";
|
|
105
|
+
${layoutContent}`;
|
|
106
|
+
}
|
|
107
|
+
if (!layoutContent.includes("<Toaster")) {
|
|
108
|
+
layoutContent = layoutContent.replace(
|
|
109
|
+
/<\/body>/,
|
|
110
|
+
" <Toaster />\n </body>"
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
fs.writeFileSync(layoutPath, layoutContent, "utf-8");
|
|
114
|
+
}
|
|
115
|
+
console.log(chalk.green("\nSetup completed!\n"));
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.log(chalk.red("\nauthUi setup failed:"), error);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// script/prisma.ts
|
|
122
|
+
var prismaRun = async ({ authUi, database }) => {
|
|
123
|
+
try {
|
|
124
|
+
console.log(chalk2.cyan("\n\u2699\uFE0F Initializing Prisma...\n"));
|
|
125
|
+
if (database !== "Mongodb") {
|
|
126
|
+
execSync2("npm install prisma --save-dev", { stdio: "inherit" });
|
|
127
|
+
execSync2("npm install @prisma/client", { stdio: "inherit" });
|
|
128
|
+
if (database === "Mysql") {
|
|
129
|
+
execSync2("npm install @prisma/adapter-mariadb", { stdio: "inherit" });
|
|
130
|
+
}
|
|
131
|
+
if (database === "Postgresql") {
|
|
132
|
+
execSync2("npm install @prisma/adapter-pg", { stdio: "inherit" });
|
|
133
|
+
}
|
|
134
|
+
} else if (database === "Mongodb") {
|
|
135
|
+
execSync2("npm install prisma@6.19.0 --save-dev", { stdio: "inherit" });
|
|
136
|
+
execSync2("npm install @prisma/client@6.19.0", { stdio: "inherit" });
|
|
137
|
+
}
|
|
138
|
+
const projectDir = process.cwd();
|
|
139
|
+
const prismaDir = path2.join(projectDir, "prisma");
|
|
140
|
+
if (!fs2.existsSync(prismaDir)) {
|
|
141
|
+
console.log(chalk2.yellow("\n\u2699\uFE0F Initializing Prisma...\n"));
|
|
142
|
+
execSync2("npx prisma init", { stdio: "inherit" });
|
|
143
|
+
}
|
|
144
|
+
const __filename = fileURLToPath2(import.meta.url);
|
|
145
|
+
const __dirname = path2.dirname(__filename);
|
|
146
|
+
const templatePath = path2.resolve(
|
|
147
|
+
__dirname,
|
|
148
|
+
`./template/prisma/${database}/schema.prisma`
|
|
149
|
+
);
|
|
150
|
+
if (!fs2.existsSync(prismaDir)) {
|
|
151
|
+
fs2.mkdirSync(prismaDir, { recursive: true });
|
|
152
|
+
}
|
|
153
|
+
const destinationPath = path2.join(prismaDir, "schema.prisma");
|
|
154
|
+
fs2.copyFileSync(templatePath, destinationPath);
|
|
155
|
+
if (database === "Mongodb") {
|
|
156
|
+
const prismaConfigPath = path2.resolve(
|
|
157
|
+
__dirname,
|
|
158
|
+
`./template/config/prisma.config.ts`
|
|
159
|
+
);
|
|
160
|
+
const prismaConfigDestinationPath = path2.join("", "prisma.config.ts");
|
|
161
|
+
fs2.copyFileSync(prismaConfigPath, prismaConfigDestinationPath);
|
|
162
|
+
}
|
|
163
|
+
console.log(chalk2.yellow("\n\u2699\uFE0F Initializing better-auth...\n"));
|
|
164
|
+
execSync2("npm install better-auth", { stdio: "inherit" });
|
|
165
|
+
const secret = await GenerateSecret();
|
|
166
|
+
const envPath = path2.join(projectDir, ".env");
|
|
167
|
+
fs2.appendFileSync(envPath, `
|
|
168
|
+
|
|
169
|
+
BETTER_AUTH_SECRET=${secret}`);
|
|
170
|
+
fs2.appendFileSync(envPath, `
|
|
171
|
+
BETTER_AUTH_URL=http://localhost:3000
|
|
172
|
+
`);
|
|
173
|
+
console.log(chalk2.yellow("\n create folder...\n"));
|
|
174
|
+
const srcPath = path2.join(projectDir, "src");
|
|
175
|
+
const folder = srcPath ? "" : "src";
|
|
176
|
+
const libPath = path2.join(projectDir, folder, "lib");
|
|
177
|
+
if (!fs2.existsSync(libPath)) {
|
|
178
|
+
fs2.mkdirSync(libPath, { recursive: true });
|
|
179
|
+
}
|
|
180
|
+
const authTemplatePath = path2.resolve(
|
|
181
|
+
__dirname,
|
|
182
|
+
`./template/lib/${database}/auth.ts`
|
|
183
|
+
);
|
|
184
|
+
const authDestinationPath = path2.join(libPath, "auth.ts");
|
|
185
|
+
fs2.copyFileSync(authTemplatePath, authDestinationPath);
|
|
186
|
+
const authClientTemplatePath = path2.resolve(
|
|
187
|
+
__dirname,
|
|
188
|
+
"./template/lib/auth-client.ts"
|
|
189
|
+
);
|
|
190
|
+
const authClientDestinationPath = path2.join(libPath, "auth-client.ts");
|
|
191
|
+
fs2.copyFileSync(authClientTemplatePath, authClientDestinationPath);
|
|
192
|
+
const serverPath = path2.join(projectDir, folder, "server");
|
|
193
|
+
if (!fs2.existsSync(serverPath)) {
|
|
194
|
+
fs2.mkdirSync(serverPath, { recursive: true });
|
|
195
|
+
}
|
|
196
|
+
const userTemplatePath = path2.resolve(
|
|
197
|
+
__dirname,
|
|
198
|
+
"./template/server/user.ts"
|
|
199
|
+
);
|
|
200
|
+
const userDestinationPath = path2.join(serverPath, "user.ts");
|
|
201
|
+
fs2.copyFileSync(userTemplatePath, userDestinationPath);
|
|
202
|
+
const routeTemplatePath = path2.resolve(
|
|
203
|
+
__dirname,
|
|
204
|
+
"./template/api/route.ts"
|
|
205
|
+
);
|
|
206
|
+
const routeDestinationDir = path2.join(
|
|
207
|
+
projectDir,
|
|
208
|
+
"app",
|
|
209
|
+
"api",
|
|
210
|
+
"auth",
|
|
211
|
+
"[...all]"
|
|
212
|
+
);
|
|
213
|
+
if (!fs2.existsSync(routeDestinationDir)) {
|
|
214
|
+
fs2.mkdirSync(routeDestinationDir, { recursive: true });
|
|
215
|
+
}
|
|
216
|
+
const routeDestinationPath = path2.join(routeDestinationDir, "route.ts");
|
|
217
|
+
fs2.copyFileSync(routeTemplatePath, routeDestinationPath);
|
|
218
|
+
const proxyTemplatePath = path2.resolve(
|
|
219
|
+
__dirname,
|
|
220
|
+
"./template/proxy/proxy.ts"
|
|
221
|
+
);
|
|
222
|
+
const proxyDestinationDir = path2.join(projectDir, folder);
|
|
223
|
+
const proxyDestinationPath = path2.join(proxyDestinationDir, "proxy.ts");
|
|
224
|
+
fs2.copyFileSync(proxyTemplatePath, proxyDestinationPath);
|
|
225
|
+
if (authUi) {
|
|
226
|
+
await authUiRun({ folder });
|
|
227
|
+
} else {
|
|
228
|
+
console.log(
|
|
229
|
+
chalk2.green(
|
|
230
|
+
"\nPrisma setup completed successfully and better-auth installed\n"
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error(chalk2.red("Prisma setup failed:"), err);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// script/drizzleRun.ts
|
|
240
|
+
import chalk3 from "chalk";
|
|
241
|
+
import { execSync as execSync3 } from "child_process";
|
|
242
|
+
import path3 from "path";
|
|
243
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
244
|
+
import fs3 from "fs";
|
|
245
|
+
var drizzleRun = async (authUi) => {
|
|
246
|
+
try {
|
|
247
|
+
console.log(chalk3.cyan("\n\u2699\uFE0F Initializing better auth and drizzle...\n"));
|
|
248
|
+
execSync3("npm install better-auth", { stdio: "inherit" });
|
|
249
|
+
execSync3("npm install drizzle-orm @neondatabase/serverless dotenv", {
|
|
250
|
+
stdio: "inherit"
|
|
251
|
+
});
|
|
252
|
+
execSync3("npm install -D drizzle-kit", { stdio: "inherit" });
|
|
253
|
+
const __filename = fileURLToPath3(import.meta.url);
|
|
254
|
+
const __dirname = path3.dirname(__filename);
|
|
255
|
+
const projectDir = process.cwd();
|
|
256
|
+
const envPath = path3.join(projectDir, ".env");
|
|
257
|
+
if (!fs3.existsSync(envPath)) {
|
|
258
|
+
fs3.writeFileSync(envPath, "DATABASE_URL=\n");
|
|
259
|
+
}
|
|
260
|
+
const secret = await GenerateSecret();
|
|
261
|
+
fs3.appendFileSync(envPath, `
|
|
262
|
+
|
|
263
|
+
BETTER_AUTH_SECRET=${secret}`);
|
|
264
|
+
fs3.appendFileSync(envPath, `
|
|
265
|
+
BETTER_AUTH_URL=http://localhost:3000
|
|
266
|
+
`);
|
|
267
|
+
const srcPath = path3.join(projectDir, "src");
|
|
268
|
+
const folder = srcPath ? "" : "src";
|
|
269
|
+
const libPath = path3.join(projectDir, folder, "lib");
|
|
270
|
+
if (!fs3.existsSync(libPath)) {
|
|
271
|
+
fs3.mkdirSync(libPath, { recursive: true });
|
|
272
|
+
}
|
|
273
|
+
const authTemplatePath = path3.resolve(
|
|
274
|
+
__dirname,
|
|
275
|
+
"./template/lib/auth-drizzle.ts"
|
|
276
|
+
);
|
|
277
|
+
const authDestinationPath = path3.join(libPath, "auth.ts");
|
|
278
|
+
fs3.copyFileSync(authTemplatePath, authDestinationPath);
|
|
279
|
+
const authClientTemplatePath = path3.resolve(
|
|
280
|
+
__dirname,
|
|
281
|
+
"./template/lib/auth-client.ts"
|
|
282
|
+
);
|
|
283
|
+
const authClientDestinationPath = path3.join(libPath, "auth-client.ts");
|
|
284
|
+
fs3.copyFileSync(authClientTemplatePath, authClientDestinationPath);
|
|
285
|
+
const dbTemplatePath = path3.resolve(__dirname, "./template/db");
|
|
286
|
+
const dbDir = path3.join(projectDir, folder, "db");
|
|
287
|
+
if (!fs3.existsSync(dbDir)) {
|
|
288
|
+
fs3.mkdirSync(dbDir, { recursive: true });
|
|
289
|
+
}
|
|
290
|
+
const dbDestinationPath = path3.join(dbDir, "drizzle.ts");
|
|
291
|
+
fs3.copyFileSync(`${dbTemplatePath}/drizzle.ts`, dbDestinationPath);
|
|
292
|
+
const schemaDestinationPath = path3.join(dbDir, "schema.ts");
|
|
293
|
+
fs3.copyFileSync(`${dbTemplatePath}/schema.ts`, schemaDestinationPath);
|
|
294
|
+
const drizzleConfigTemplatePath = path3.resolve(
|
|
295
|
+
__dirname,
|
|
296
|
+
"./template/config/drizzle.config.ts"
|
|
297
|
+
);
|
|
298
|
+
const drizzleConfigDestinationPath = path3.join(
|
|
299
|
+
projectDir,
|
|
300
|
+
"drizzle.config.ts"
|
|
301
|
+
);
|
|
302
|
+
fs3.copyFileSync(drizzleConfigTemplatePath, drizzleConfigDestinationPath);
|
|
303
|
+
const serverPath = path3.join(projectDir, folder, "server");
|
|
304
|
+
if (!fs3.existsSync(serverPath)) {
|
|
305
|
+
fs3.mkdirSync(serverPath, { recursive: true });
|
|
306
|
+
}
|
|
307
|
+
const userTemplatePath = path3.resolve(
|
|
308
|
+
__dirname,
|
|
309
|
+
"./template/server/user.ts"
|
|
310
|
+
);
|
|
311
|
+
const userDestinationPath = path3.join(serverPath, "user.ts");
|
|
312
|
+
fs3.copyFileSync(userTemplatePath, userDestinationPath);
|
|
313
|
+
const routeTemplatePath = path3.resolve(
|
|
314
|
+
__dirname,
|
|
315
|
+
"./template/api/route.ts"
|
|
316
|
+
);
|
|
317
|
+
const routeDestinationDir = path3.join(
|
|
318
|
+
projectDir,
|
|
319
|
+
"app",
|
|
320
|
+
"api",
|
|
321
|
+
"auth",
|
|
322
|
+
"[...all]"
|
|
323
|
+
);
|
|
324
|
+
if (!fs3.existsSync(routeDestinationDir)) {
|
|
325
|
+
fs3.mkdirSync(routeDestinationDir, { recursive: true });
|
|
326
|
+
}
|
|
327
|
+
const routeDestinationPath = path3.join(routeDestinationDir, "route.ts");
|
|
328
|
+
fs3.copyFileSync(routeTemplatePath, routeDestinationPath);
|
|
329
|
+
const proxyTemplatePath = path3.resolve(
|
|
330
|
+
__dirname,
|
|
331
|
+
"./template/proxy/proxy.ts"
|
|
332
|
+
);
|
|
333
|
+
const proxyDestinationDir = path3.join(projectDir, folder);
|
|
334
|
+
const proxyDestinationPath = path3.join(proxyDestinationDir, "proxy.ts");
|
|
335
|
+
fs3.copyFileSync(proxyTemplatePath, proxyDestinationPath);
|
|
336
|
+
if (authUi) {
|
|
337
|
+
await authUiRun({ folder });
|
|
338
|
+
} else {
|
|
339
|
+
console.log(
|
|
340
|
+
chalk3.green(
|
|
341
|
+
"\nDrizzle setup completed successfully and better-auth installed\n"
|
|
342
|
+
)
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
} catch (err) {
|
|
346
|
+
console.error(chalk3.red("Drizzle setup failed:"), err);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// cli/init.ts
|
|
351
|
+
var initAnswer = async () => {
|
|
352
|
+
const answers = await inquirer.prompt([
|
|
353
|
+
{
|
|
354
|
+
type: "list",
|
|
355
|
+
name: "orm",
|
|
356
|
+
message: "Choose Your ORM:",
|
|
357
|
+
choices: ["Prisma", "Drizzle"]
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
type: "list",
|
|
361
|
+
name: "database",
|
|
362
|
+
message: "Select Database:",
|
|
363
|
+
choices: ["Postgresql", "Mongodb", "Mysql"],
|
|
364
|
+
when: (ans) => ans.orm === "Prisma"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
type: "confirm",
|
|
368
|
+
name: "authUi",
|
|
369
|
+
message: "Do you want to include auth UI design?",
|
|
370
|
+
default: true
|
|
371
|
+
}
|
|
372
|
+
]);
|
|
373
|
+
if (answers.orm === "Prisma") {
|
|
374
|
+
await prismaRun({
|
|
375
|
+
authUi: answers.authUi,
|
|
376
|
+
database: answers.database
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
if (answers.orm === "Drizzle") {
|
|
380
|
+
await drizzleRun(answers.authUi);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// index.ts
|
|
385
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
386
|
+
|
|
387
|
+
// cli/provider.ts
|
|
388
|
+
import chalk6 from "chalk";
|
|
389
|
+
|
|
390
|
+
// script/googleRun.ts
|
|
391
|
+
import chalk4 from "chalk";
|
|
392
|
+
import { execSync as execSync4 } from "child_process";
|
|
393
|
+
import fs4 from "fs";
|
|
394
|
+
import path4 from "path";
|
|
395
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
396
|
+
var googleRun = async () => {
|
|
397
|
+
try {
|
|
398
|
+
execSync4("npm install react-icons --save", { stdio: "inherit" });
|
|
399
|
+
const __filename = fileURLToPath4(import.meta.url);
|
|
400
|
+
const __dirname = path4.dirname(__filename);
|
|
401
|
+
const projectDir = process.cwd();
|
|
402
|
+
const srcPath = path4.join(projectDir, "src");
|
|
403
|
+
const folder = srcPath ? "" : "src";
|
|
404
|
+
const authFilePath = path4.join(projectDir, folder, "lib", "auth.ts");
|
|
405
|
+
if (!fs4.existsSync(authFilePath)) {
|
|
406
|
+
console.log(chalk4.red("auth.ts file not found."));
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
let content = fs4.readFileSync(authFilePath, "utf8");
|
|
410
|
+
const socialProvidersCode = `
|
|
411
|
+
socialProviders: {
|
|
412
|
+
google: {
|
|
413
|
+
clientId: process.env.GOOGLE_CLIENT_ID as string,
|
|
414
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
|
|
415
|
+
},
|
|
416
|
+
}`;
|
|
417
|
+
if (content.includes("betterAuth({")) {
|
|
418
|
+
content = content.replace(/betterAuth\(\{([\s\S]*?)\}\)/, (inner) => {
|
|
419
|
+
return `
|
|
420
|
+
${inner.trimEnd()},${socialProvidersCode}`;
|
|
421
|
+
});
|
|
422
|
+
fs4.writeFileSync(authFilePath, content, "utf8");
|
|
423
|
+
const envPath = path4.join(projectDir, ".env");
|
|
424
|
+
fs4.appendFileSync(envPath, `
|
|
425
|
+
|
|
426
|
+
# Google OAuth Credentials`);
|
|
427
|
+
fs4.appendFileSync(envPath, `
|
|
428
|
+
GOOGLE_CLIENT_ID=`);
|
|
429
|
+
fs4.appendFileSync(envPath, `
|
|
430
|
+
GOOGLE_CLIENT_SECRET=`);
|
|
431
|
+
const componentPath = path4.resolve(
|
|
432
|
+
__dirname,
|
|
433
|
+
"./template/components/GoogleProviders.tsx"
|
|
434
|
+
);
|
|
435
|
+
const destinationPath = path4.join(
|
|
436
|
+
projectDir,
|
|
437
|
+
folder,
|
|
438
|
+
"components",
|
|
439
|
+
"authverse"
|
|
440
|
+
);
|
|
441
|
+
if (!fs4.existsSync(destinationPath)) {
|
|
442
|
+
fs4.mkdirSync(destinationPath, { recursive: true });
|
|
443
|
+
}
|
|
444
|
+
const LoginDestinationPath = path4.join(
|
|
445
|
+
destinationPath,
|
|
446
|
+
"GoogleProviders.tsx"
|
|
447
|
+
);
|
|
448
|
+
fs4.copyFileSync(componentPath, LoginDestinationPath);
|
|
449
|
+
console.log(
|
|
450
|
+
chalk4.green("Added socialProviders with Google provider successfully")
|
|
451
|
+
);
|
|
452
|
+
} else {
|
|
453
|
+
console.log(chalk4.red("Could not find betterAuth({ }) block in auth.ts"));
|
|
454
|
+
}
|
|
455
|
+
} catch (error) {
|
|
456
|
+
console.log(chalk4.red("Error adding socialProviders:"), error);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// script/githubRun.ts
|
|
461
|
+
import chalk5 from "chalk";
|
|
462
|
+
import { execSync as execSync5 } from "child_process";
|
|
463
|
+
import fs5 from "fs";
|
|
464
|
+
import path5 from "path";
|
|
465
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
466
|
+
var githubRun = async () => {
|
|
467
|
+
try {
|
|
468
|
+
execSync5("npm install react-icons --save", { stdio: "inherit" });
|
|
469
|
+
const __filename = fileURLToPath5(import.meta.url);
|
|
470
|
+
const __dirname = path5.dirname(__filename);
|
|
471
|
+
const projectDir = process.cwd();
|
|
472
|
+
const srcPath = path5.join(projectDir, "src");
|
|
473
|
+
const folder = fs5.existsSync(srcPath) ? "src" : "";
|
|
474
|
+
const authFilePath = path5.join(projectDir, folder, "lib", "auth.ts");
|
|
475
|
+
if (!fs5.existsSync(authFilePath)) {
|
|
476
|
+
console.log(chalk5.red("auth.ts file not found."));
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
let content = fs5.readFileSync(authFilePath, "utf8");
|
|
480
|
+
const githubProviderCode = `github: {
|
|
481
|
+
clientId: process.env.GITHUB_CLIENT_ID as string,
|
|
482
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
|
|
483
|
+
},`;
|
|
484
|
+
if (content.includes("betterAuth({")) {
|
|
485
|
+
if (content.includes("socialProviders:")) {
|
|
486
|
+
const socialProvidersStart = content.indexOf("socialProviders: {");
|
|
487
|
+
let socialProvidersEnd = socialProvidersStart;
|
|
488
|
+
let braceCount = 0;
|
|
489
|
+
let inSocialProviders = false;
|
|
490
|
+
for (let i = socialProvidersStart; i < content.length; i++) {
|
|
491
|
+
if (content[i] === "{") {
|
|
492
|
+
braceCount++;
|
|
493
|
+
inSocialProviders = true;
|
|
494
|
+
} else if (content[i] === "}") {
|
|
495
|
+
braceCount--;
|
|
496
|
+
if (inSocialProviders && braceCount === 0) {
|
|
497
|
+
socialProvidersEnd = i;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const before = content.substring(0, socialProvidersEnd);
|
|
503
|
+
const after = content.substring(socialProvidersEnd);
|
|
504
|
+
content = before + `${githubProviderCode}
|
|
505
|
+
` + after;
|
|
506
|
+
} else {
|
|
507
|
+
const insertPosition = content.search(
|
|
508
|
+
/(?=,\s*(plugins|emailAndPassword|session|database|$|\n\s*\}\)))/
|
|
509
|
+
);
|
|
510
|
+
if (insertPosition !== -1) {
|
|
511
|
+
const before = content.substring(0, insertPosition);
|
|
512
|
+
const after = content.substring(insertPosition);
|
|
513
|
+
content = before + `,
|
|
514
|
+
socialProviders: {
|
|
515
|
+
${githubProviderCode}
|
|
516
|
+
}` + after;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
fs5.writeFileSync(authFilePath, content, "utf8");
|
|
520
|
+
const envPath = path5.join(projectDir, ".env");
|
|
521
|
+
if (fs5.existsSync(envPath)) {
|
|
522
|
+
fs5.appendFileSync(envPath, `
|
|
523
|
+
|
|
524
|
+
# Github OAuth Credentials`);
|
|
525
|
+
fs5.appendFileSync(envPath, `
|
|
526
|
+
GITHUB_CLIENT_ID=`);
|
|
527
|
+
fs5.appendFileSync(envPath, `
|
|
528
|
+
GITHUB_CLIENT_SECRET=`);
|
|
529
|
+
}
|
|
530
|
+
const componentPath = path5.resolve(
|
|
531
|
+
__dirname,
|
|
532
|
+
"./template/components/GithubProviders.tsx"
|
|
533
|
+
);
|
|
534
|
+
const destinationPath = path5.join(
|
|
535
|
+
projectDir,
|
|
536
|
+
folder,
|
|
537
|
+
"components",
|
|
538
|
+
"authverse"
|
|
539
|
+
);
|
|
540
|
+
if (!fs5.existsSync(destinationPath)) {
|
|
541
|
+
fs5.mkdirSync(destinationPath, { recursive: true });
|
|
542
|
+
}
|
|
543
|
+
const LoginDestinationPath = path5.join(
|
|
544
|
+
destinationPath,
|
|
545
|
+
"GithubProviders.tsx"
|
|
546
|
+
);
|
|
547
|
+
if (fs5.existsSync(componentPath)) {
|
|
548
|
+
fs5.copyFileSync(componentPath, LoginDestinationPath);
|
|
549
|
+
}
|
|
550
|
+
console.log(
|
|
551
|
+
chalk5.green("Added socialProviders with Github provider successfully")
|
|
552
|
+
);
|
|
553
|
+
} else {
|
|
554
|
+
console.log(chalk5.red("Could not find betterAuth({ }) block in auth.ts"));
|
|
555
|
+
}
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.log(chalk5.red("Error adding socialProviders:"), error);
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// cli/provider.ts
|
|
562
|
+
var providers = async ({ provider }) => {
|
|
563
|
+
try {
|
|
564
|
+
if (provider == "google") {
|
|
565
|
+
await googleRun();
|
|
566
|
+
} else if (provider == "github") {
|
|
567
|
+
await githubRun();
|
|
568
|
+
}
|
|
569
|
+
} catch (error) {
|
|
570
|
+
console.log(chalk6.red("Error adding provider:"), error);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// cli/forget.ts
|
|
575
|
+
import chalk7 from "chalk";
|
|
576
|
+
import { execSync as execSync6 } from "child_process";
|
|
577
|
+
import path6 from "path";
|
|
578
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
579
|
+
import fs6 from "fs";
|
|
580
|
+
var forget = async () => {
|
|
581
|
+
try {
|
|
582
|
+
execSync6("npm install @react-email/components resend", {
|
|
583
|
+
stdio: "inherit"
|
|
584
|
+
});
|
|
585
|
+
const __filename = fileURLToPath6(import.meta.url);
|
|
586
|
+
const __dirname = path6.dirname(__filename);
|
|
587
|
+
const projectDir = process.cwd();
|
|
588
|
+
const srcPath = path6.join(projectDir, "src");
|
|
589
|
+
const folder = fs6.existsSync(srcPath) ? "src" : "";
|
|
590
|
+
const authFilePath = path6.join(projectDir, folder, "lib", "auth.ts");
|
|
591
|
+
if (!fs6.existsSync(authFilePath)) {
|
|
592
|
+
console.log(chalk7.red("auth.ts file not found."));
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
let content = fs6.readFileSync(authFilePath, "utf8");
|
|
596
|
+
const codeAdded = `sendResetPassword: async ({ user, url, token }) => {
|
|
597
|
+
await resend.emails.send({
|
|
598
|
+
from: \`\${process.env.EMAIL_SENDER_NAME} <\${process.env.EMAIL_SENDER_ADDRESS}>\`,
|
|
599
|
+
to: user.email,
|
|
600
|
+
subject: "Reset your password",
|
|
601
|
+
react: ForgotPasswordEmail({
|
|
602
|
+
username: user.name,
|
|
603
|
+
resetUrl: url,
|
|
604
|
+
userEmail: user.email,
|
|
605
|
+
}),
|
|
606
|
+
});
|
|
607
|
+
},`;
|
|
608
|
+
if (content.includes("emailAndPassword: {")) {
|
|
609
|
+
const emailAndPasswordStart = content.indexOf("emailAndPassword: {");
|
|
610
|
+
let emailAndPasswordEnd = emailAndPasswordStart;
|
|
611
|
+
let braceCount = 0;
|
|
612
|
+
let inEmailAndPassword = false;
|
|
613
|
+
for (let i = emailAndPasswordStart; i < content.length; i++) {
|
|
614
|
+
if (content[i] === "{") {
|
|
615
|
+
braceCount++;
|
|
616
|
+
inEmailAndPassword = true;
|
|
617
|
+
} else if (content[i] === "}") {
|
|
618
|
+
braceCount--;
|
|
619
|
+
if (inEmailAndPassword && braceCount === 0) {
|
|
620
|
+
emailAndPasswordEnd = i;
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
const emailAndPasswordContent = content.substring(
|
|
626
|
+
emailAndPasswordStart,
|
|
627
|
+
emailAndPasswordEnd
|
|
628
|
+
);
|
|
629
|
+
if (emailAndPasswordContent.includes("sendResetPassword:")) {
|
|
630
|
+
content = content.replace(
|
|
631
|
+
/sendResetPassword:\s*async\s*\([^)]*\)[^{]*\{[^}]*\}[^,]*/,
|
|
632
|
+
codeAdded
|
|
633
|
+
);
|
|
634
|
+
} else {
|
|
635
|
+
const before = content.substring(0, emailAndPasswordEnd);
|
|
636
|
+
const after = content.substring(emailAndPasswordEnd);
|
|
637
|
+
content = before + `
|
|
638
|
+
${codeAdded}` + after;
|
|
639
|
+
}
|
|
640
|
+
fs6.writeFileSync(authFilePath, content, "utf8");
|
|
641
|
+
if (!content.includes("import { Resend }") && !content.includes("const resend = new Resend")) {
|
|
642
|
+
const lastImportIndex = content.lastIndexOf("import");
|
|
643
|
+
const nextLineAfterLastImport = content.indexOf("\n", lastImportIndex) + 1;
|
|
644
|
+
const beforeImports = content.substring(0, nextLineAfterLastImport);
|
|
645
|
+
const afterImports = content.substring(nextLineAfterLastImport);
|
|
646
|
+
const newImports = `import { Resend } from "resend";
|
|
647
|
+
import ForgotPasswordEmail from "@/components/email/reset-password";
|
|
648
|
+
|
|
649
|
+
const resend = new Resend(process.env.RESEND_API_KEY as string);
|
|
650
|
+
`;
|
|
651
|
+
content = beforeImports + newImports + afterImports;
|
|
652
|
+
fs6.writeFileSync(authFilePath, content, "utf8");
|
|
653
|
+
}
|
|
654
|
+
const envPath = path6.join(projectDir, ".env");
|
|
655
|
+
if (fs6.existsSync(envPath)) {
|
|
656
|
+
fs6.appendFileSync(envPath, `
|
|
657
|
+
|
|
658
|
+
# Resend API Key for sending emails`);
|
|
659
|
+
fs6.appendFileSync(envPath, `
|
|
660
|
+
RESEND_API_KEY=`);
|
|
661
|
+
fs6.appendFileSync(envPath, `
|
|
662
|
+
EMAIL_SENDER_NAME=Your Name`);
|
|
663
|
+
fs6.appendFileSync(envPath, `
|
|
664
|
+
EMAIL_SENDER_ADDRESS=`);
|
|
665
|
+
}
|
|
666
|
+
const componentPath = path6.resolve(
|
|
667
|
+
__dirname,
|
|
668
|
+
"./template/email/reset-password.tsx"
|
|
669
|
+
);
|
|
670
|
+
const destinationPath = path6.join(
|
|
671
|
+
projectDir,
|
|
672
|
+
folder,
|
|
673
|
+
"components",
|
|
674
|
+
"email"
|
|
675
|
+
);
|
|
676
|
+
if (!fs6.existsSync(destinationPath)) {
|
|
677
|
+
fs6.mkdirSync(destinationPath, { recursive: true });
|
|
678
|
+
}
|
|
679
|
+
const emailDestinationPath = path6.join(
|
|
680
|
+
destinationPath,
|
|
681
|
+
"reset-password.tsx"
|
|
682
|
+
);
|
|
683
|
+
if (fs6.existsSync(componentPath)) {
|
|
684
|
+
fs6.copyFileSync(componentPath, emailDestinationPath);
|
|
685
|
+
}
|
|
686
|
+
const forgetComponentPath = path6.resolve(
|
|
687
|
+
__dirname,
|
|
688
|
+
"./template/components/ForgetComponent.tsx"
|
|
689
|
+
);
|
|
690
|
+
const componentsDestinationPath = path6.join(
|
|
691
|
+
projectDir,
|
|
692
|
+
folder,
|
|
693
|
+
"components",
|
|
694
|
+
"authverse"
|
|
695
|
+
);
|
|
696
|
+
if (!fs6.existsSync(componentsDestinationPath)) {
|
|
697
|
+
fs6.mkdirSync(componentsDestinationPath, { recursive: true });
|
|
698
|
+
}
|
|
699
|
+
const forgetDestinationPath = path6.join(
|
|
700
|
+
componentsDestinationPath,
|
|
701
|
+
"ForgetComponent.tsx"
|
|
702
|
+
);
|
|
703
|
+
if (fs6.existsSync(forgetComponentPath)) {
|
|
704
|
+
fs6.copyFileSync(forgetComponentPath, forgetDestinationPath);
|
|
705
|
+
}
|
|
706
|
+
const resetComponentPath = path6.resolve(
|
|
707
|
+
__dirname,
|
|
708
|
+
"./template/components/ResetComponent.tsx"
|
|
709
|
+
);
|
|
710
|
+
const resetDestinationPath = path6.join(
|
|
711
|
+
componentsDestinationPath,
|
|
712
|
+
"ResetComponent.tsx"
|
|
713
|
+
);
|
|
714
|
+
if (fs6.existsSync(resetComponentPath)) {
|
|
715
|
+
fs6.copyFileSync(resetComponentPath, resetDestinationPath);
|
|
716
|
+
}
|
|
717
|
+
const authTemplatePath = path6.resolve(
|
|
718
|
+
__dirname,
|
|
719
|
+
"./template/app-auth-uiDesign"
|
|
720
|
+
);
|
|
721
|
+
const appDestinationPath = path6.join(projectDir, folder, "app", "auth");
|
|
722
|
+
if (!fs6.existsSync(appDestinationPath)) {
|
|
723
|
+
fs6.mkdirSync(appDestinationPath, { recursive: true });
|
|
724
|
+
}
|
|
725
|
+
const forgetDestinationDir = path6.join(appDestinationPath, "forget");
|
|
726
|
+
if (!fs6.existsSync(forgetDestinationDir)) {
|
|
727
|
+
fs6.mkdirSync(forgetDestinationDir, { recursive: true });
|
|
728
|
+
}
|
|
729
|
+
const forgetPageDestinationPath = path6.join(
|
|
730
|
+
forgetDestinationDir,
|
|
731
|
+
"page.tsx"
|
|
732
|
+
);
|
|
733
|
+
fs6.copyFileSync(
|
|
734
|
+
`${authTemplatePath}/forget/page.tsx`,
|
|
735
|
+
forgetPageDestinationPath
|
|
736
|
+
);
|
|
737
|
+
const resetDestinationDir = path6.join(
|
|
738
|
+
appDestinationPath,
|
|
739
|
+
"reset-password"
|
|
740
|
+
);
|
|
741
|
+
if (!fs6.existsSync(resetDestinationDir)) {
|
|
742
|
+
fs6.mkdirSync(resetDestinationDir, { recursive: true });
|
|
743
|
+
}
|
|
744
|
+
const resetPageDestinationPath = path6.join(
|
|
745
|
+
resetDestinationDir,
|
|
746
|
+
"page.tsx"
|
|
747
|
+
);
|
|
748
|
+
fs6.copyFileSync(
|
|
749
|
+
`${authTemplatePath}/reset-password/page.tsx`,
|
|
750
|
+
resetPageDestinationPath
|
|
751
|
+
);
|
|
752
|
+
console.log(
|
|
753
|
+
chalk7.green("Added sendResetPassword configuration successfully")
|
|
754
|
+
);
|
|
755
|
+
} else {
|
|
756
|
+
console.log(
|
|
757
|
+
chalk7.red("Could not find emailAndPassword configuration in auth.ts")
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
} catch (error) {
|
|
761
|
+
console.log(chalk7.red("Error adding sendResetPassword:"), error);
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
// script/detect-nextjs.ts
|
|
766
|
+
import { existsSync, readFileSync } from "fs";
|
|
767
|
+
function isNextJsProject() {
|
|
768
|
+
if (!existsSync("./package.json")) return false;
|
|
769
|
+
try {
|
|
770
|
+
const pkg = JSON.parse(readFileSync("./package.json", "utf8"));
|
|
771
|
+
const deps = {
|
|
772
|
+
...pkg.dependencies,
|
|
773
|
+
...pkg.devDependencies
|
|
774
|
+
};
|
|
775
|
+
return deps["next"] !== void 0;
|
|
776
|
+
} catch (err) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// index.ts
|
|
782
|
+
import chalk8 from "chalk";
|
|
783
|
+
var packageJson = JSON.parse(readFileSync2("./package.json", "utf8"));
|
|
784
|
+
var program = new Command();
|
|
785
|
+
program.name("authverse").description("CLI tool for creating authverse projects").version(
|
|
786
|
+
packageJson.version || "1.0.0",
|
|
787
|
+
"-v, --version",
|
|
788
|
+
"display the version number"
|
|
789
|
+
);
|
|
790
|
+
program.command("init").description("Select project template and configuration").action(() => {
|
|
791
|
+
if (!isNextJsProject) {
|
|
792
|
+
console.log(chalk8.red("Only Next.js projects are supported."));
|
|
793
|
+
process.exit(1);
|
|
794
|
+
}
|
|
795
|
+
initAnswer();
|
|
796
|
+
});
|
|
797
|
+
program.command("add <provider>").description("Add a new authentication provider").action((provider) => providers({ provider }));
|
|
798
|
+
program.command("forget").description("Forget stored configurations").action(forget);
|
|
799
|
+
program.parse(process.argv);
|