@better-auth/cli 1.4.0-beta.5 → 1.4.0-beta.7
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/dist/index.mjs +280 -89
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -4,8 +4,10 @@ import { parse } from 'dotenv';
|
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
import prettier, { format } from 'prettier';
|
|
6
6
|
import * as z from 'zod/v4';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import fs__default, { existsSync, readFileSync } from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import path__default from 'path';
|
|
9
11
|
import fs$1 from 'fs/promises';
|
|
10
12
|
import chalk from 'chalk';
|
|
11
13
|
import { intro, log, outro, confirm, isCancel, cancel, spinner, text, select, multiselect } from '@clack/prompts';
|
|
@@ -22,12 +24,14 @@ import { produceSchema } from '@mrleebo/prisma-ast';
|
|
|
22
24
|
import { createAuthClient } from 'better-auth/client';
|
|
23
25
|
import { deviceAuthorizationClient } from 'better-auth/client/plugins';
|
|
24
26
|
import open from 'open';
|
|
25
|
-
import os from 'os';
|
|
27
|
+
import * as os from 'os';
|
|
28
|
+
import os__default from 'os';
|
|
29
|
+
import { base64 } from '@better-auth/utils/base64';
|
|
26
30
|
import 'dotenv/config';
|
|
27
31
|
|
|
28
32
|
function getPackageInfo(cwd) {
|
|
29
|
-
const packageJsonPath = cwd ?
|
|
30
|
-
return JSON.parse(
|
|
33
|
+
const packageJsonPath = cwd ? path__default.join(cwd, "package.json") : path__default.join("package.json");
|
|
34
|
+
return JSON.parse(fs__default.readFileSync(packageJsonPath, "utf-8"));
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
function installDependencies({
|
|
@@ -678,10 +682,10 @@ function getTsconfigInfo(cwd, flatPath) {
|
|
|
678
682
|
if (flatPath) {
|
|
679
683
|
tsConfigPath = flatPath;
|
|
680
684
|
} else {
|
|
681
|
-
tsConfigPath = cwd ?
|
|
685
|
+
tsConfigPath = cwd ? path__default.join(cwd, "tsconfig.json") : path__default.join("tsconfig.json");
|
|
682
686
|
}
|
|
683
687
|
try {
|
|
684
|
-
const text =
|
|
688
|
+
const text = fs__default.readFileSync(tsConfigPath, "utf-8");
|
|
685
689
|
return JSON.parse(stripJsonComments(text));
|
|
686
690
|
} catch (error) {
|
|
687
691
|
throw error;
|
|
@@ -965,7 +969,7 @@ async function initAction(opts) {
|
|
|
965
969
|
console.log();
|
|
966
970
|
intro("\u{1F44B} Initializing Better Auth");
|
|
967
971
|
const options = optionsSchema.parse(opts);
|
|
968
|
-
const cwd =
|
|
972
|
+
const cwd = path__default.resolve(options.cwd);
|
|
969
973
|
let packageManagerPreference = void 0;
|
|
970
974
|
let config_path = "";
|
|
971
975
|
let framework = "vanilla";
|
|
@@ -995,7 +999,7 @@ async function initAction(opts) {
|
|
|
995
999
|
else targetEnvFile = "none";
|
|
996
1000
|
let tsconfigInfo;
|
|
997
1001
|
try {
|
|
998
|
-
const tsconfigPath = options.tsconfig !== void 0 ?
|
|
1002
|
+
const tsconfigPath = options.tsconfig !== void 0 ? path__default.resolve(cwd, options.tsconfig) : path__default.join(cwd, "tsconfig.json");
|
|
999
1003
|
tsconfigInfo = await getTsconfigInfo(cwd, tsconfigPath);
|
|
1000
1004
|
} catch (error) {
|
|
1001
1005
|
log.error(`\u274C Couldn't read your tsconfig.json file. (dir: ${cwd})`);
|
|
@@ -1018,7 +1022,7 @@ async function initAction(opts) {
|
|
|
1018
1022
|
if (shouldAdd) {
|
|
1019
1023
|
try {
|
|
1020
1024
|
await fs$1.writeFile(
|
|
1021
|
-
|
|
1025
|
+
path__default.join(cwd, "tsconfig.json"),
|
|
1022
1026
|
await format(
|
|
1023
1027
|
JSON.stringify(
|
|
1024
1028
|
Object.assign(tsconfigInfo, {
|
|
@@ -1157,12 +1161,12 @@ async function initAction(opts) {
|
|
|
1157
1161
|
...possiblePaths.map((it) => `app/${it}`)
|
|
1158
1162
|
];
|
|
1159
1163
|
if (options.config) {
|
|
1160
|
-
config_path =
|
|
1164
|
+
config_path = path__default.join(cwd, options.config);
|
|
1161
1165
|
} else {
|
|
1162
1166
|
for (const possiblePath of possiblePaths) {
|
|
1163
|
-
const doesExist = existsSync(
|
|
1167
|
+
const doesExist = existsSync(path__default.join(cwd, possiblePath));
|
|
1164
1168
|
if (doesExist) {
|
|
1165
|
-
config_path =
|
|
1169
|
+
config_path = path__default.join(cwd, possiblePath);
|
|
1166
1170
|
break;
|
|
1167
1171
|
}
|
|
1168
1172
|
}
|
|
@@ -1232,7 +1236,7 @@ async function initAction(opts) {
|
|
|
1232
1236
|
".next/server/next.config.mjs"
|
|
1233
1237
|
];
|
|
1234
1238
|
for (const possible_next_config_path of possible_next_config_paths) {
|
|
1235
|
-
if (existsSync(
|
|
1239
|
+
if (existsSync(path__default.join(cwd, possible_next_config_path))) {
|
|
1236
1240
|
framework = "nextjs";
|
|
1237
1241
|
break;
|
|
1238
1242
|
}
|
|
@@ -1255,7 +1259,7 @@ async function initAction(opts) {
|
|
|
1255
1259
|
}
|
|
1256
1260
|
}
|
|
1257
1261
|
}
|
|
1258
|
-
const filePath =
|
|
1262
|
+
const filePath = path__default.join(cwd, "auth.ts");
|
|
1259
1263
|
config_path = filePath;
|
|
1260
1264
|
log.info(`Creating auth config file: ${filePath}`);
|
|
1261
1265
|
try {
|
|
@@ -1289,7 +1293,7 @@ async function initAction(opts) {
|
|
|
1289
1293
|
const filesToUpdate = await multiselect({
|
|
1290
1294
|
message: "Select the .env files you want to update",
|
|
1291
1295
|
options: envFiles.map((x) => ({
|
|
1292
|
-
value:
|
|
1296
|
+
value: path__default.join(cwd, x),
|
|
1293
1297
|
label: x
|
|
1294
1298
|
})),
|
|
1295
1299
|
required: false
|
|
@@ -1397,9 +1401,9 @@ async function initAction(opts) {
|
|
|
1397
1401
|
];
|
|
1398
1402
|
let authClientConfigPath = null;
|
|
1399
1403
|
for (const possiblePath of possibleClientPaths) {
|
|
1400
|
-
const doesExist = existsSync(
|
|
1404
|
+
const doesExist = existsSync(path__default.join(cwd, possiblePath));
|
|
1401
1405
|
if (doesExist) {
|
|
1402
|
-
authClientConfigPath =
|
|
1406
|
+
authClientConfigPath = path__default.join(cwd, possiblePath);
|
|
1403
1407
|
break;
|
|
1404
1408
|
}
|
|
1405
1409
|
}
|
|
@@ -1416,11 +1420,11 @@ async function initAction(opts) {
|
|
|
1416
1420
|
process.exit(0);
|
|
1417
1421
|
}
|
|
1418
1422
|
if (choice === "yes") {
|
|
1419
|
-
authClientConfigPath =
|
|
1423
|
+
authClientConfigPath = path__default.join(cwd, "auth-client.ts");
|
|
1420
1424
|
log.info(`Creating auth client config file: ${authClientConfigPath}`);
|
|
1421
1425
|
try {
|
|
1422
1426
|
let contents = await getDefaultAuthClientConfig({
|
|
1423
|
-
auth_config_path: ("./" +
|
|
1427
|
+
auth_config_path: ("./" + path__default.join(config_path.replace(cwd, ""))).replace(".//", "./"),
|
|
1424
1428
|
clientPlugins: add_plugins.filter((x) => x.clientName).map((plugin) => {
|
|
1425
1429
|
let contents2 = "";
|
|
1426
1430
|
if (plugin.id === "one-tap") {
|
|
@@ -1462,7 +1466,7 @@ async function initAction(opts) {
|
|
|
1462
1466
|
if (targetEnvFile !== "none") {
|
|
1463
1467
|
try {
|
|
1464
1468
|
const fileContents = await fs$1.readFile(
|
|
1465
|
-
|
|
1469
|
+
path__default.join(cwd, targetEnvFile),
|
|
1466
1470
|
"utf8"
|
|
1467
1471
|
);
|
|
1468
1472
|
const parsed = parse(fileContents);
|
|
@@ -1501,7 +1505,7 @@ async function initAction(opts) {
|
|
|
1501
1505
|
if (shouldAdd === "yes") {
|
|
1502
1506
|
try {
|
|
1503
1507
|
await updateEnvs({
|
|
1504
|
-
files: [
|
|
1508
|
+
files: [path__default.join(cwd, targetEnvFile)],
|
|
1505
1509
|
envs,
|
|
1506
1510
|
isCommented: false
|
|
1507
1511
|
});
|
|
@@ -1526,7 +1530,7 @@ async function initAction(opts) {
|
|
|
1526
1530
|
const envFilesToUpdate = await multiselect({
|
|
1527
1531
|
message: "Select the .env files you want to update",
|
|
1528
1532
|
options: envFiles.map((x) => ({
|
|
1529
|
-
value:
|
|
1533
|
+
value: path__default.join(cwd, x),
|
|
1530
1534
|
label: x
|
|
1531
1535
|
})),
|
|
1532
1536
|
required: false
|
|
@@ -1678,13 +1682,13 @@ function addSvelteKitEnvModules(aliases, cwd) {
|
|
|
1678
1682
|
}
|
|
1679
1683
|
function getSvelteKitPathAliases(cwd) {
|
|
1680
1684
|
const aliases = {};
|
|
1681
|
-
const packageJsonPath =
|
|
1682
|
-
const svelteConfigPath =
|
|
1683
|
-
const svelteConfigTsPath =
|
|
1685
|
+
const packageJsonPath = path__default.join(cwd, "package.json");
|
|
1686
|
+
const svelteConfigPath = path__default.join(cwd, "svelte.config.js");
|
|
1687
|
+
const svelteConfigTsPath = path__default.join(cwd, "svelte.config.ts");
|
|
1684
1688
|
let isSvelteKitProject = false;
|
|
1685
|
-
if (
|
|
1689
|
+
if (fs__default.existsSync(packageJsonPath)) {
|
|
1686
1690
|
try {
|
|
1687
|
-
const packageJson = JSON.parse(
|
|
1691
|
+
const packageJson = JSON.parse(fs__default.readFileSync(packageJsonPath, "utf-8"));
|
|
1688
1692
|
const deps = {
|
|
1689
1693
|
...packageJson.dependencies,
|
|
1690
1694
|
...packageJson.devDependencies
|
|
@@ -1694,19 +1698,19 @@ function getSvelteKitPathAliases(cwd) {
|
|
|
1694
1698
|
}
|
|
1695
1699
|
}
|
|
1696
1700
|
if (!isSvelteKitProject) {
|
|
1697
|
-
isSvelteKitProject =
|
|
1701
|
+
isSvelteKitProject = fs__default.existsSync(svelteConfigPath) || fs__default.existsSync(svelteConfigTsPath);
|
|
1698
1702
|
}
|
|
1699
1703
|
if (!isSvelteKitProject) {
|
|
1700
1704
|
return aliases;
|
|
1701
1705
|
}
|
|
1702
|
-
const libPaths = [
|
|
1706
|
+
const libPaths = [path__default.join(cwd, "src", "lib"), path__default.join(cwd, "lib")];
|
|
1703
1707
|
for (const libPath of libPaths) {
|
|
1704
|
-
if (
|
|
1708
|
+
if (fs__default.existsSync(libPath)) {
|
|
1705
1709
|
aliases["$lib"] = libPath;
|
|
1706
1710
|
const commonSubPaths = ["server", "utils", "components", "stores"];
|
|
1707
1711
|
for (const subPath of commonSubPaths) {
|
|
1708
|
-
const subDir =
|
|
1709
|
-
if (
|
|
1712
|
+
const subDir = path__default.join(libPath, subPath);
|
|
1713
|
+
if (fs__default.existsSync(subDir)) {
|
|
1710
1714
|
aliases[`$lib/${subPath}`] = subDir;
|
|
1711
1715
|
}
|
|
1712
1716
|
}
|
|
@@ -1721,13 +1725,13 @@ function getSvelteKitPathAliases(cwd) {
|
|
|
1721
1725
|
function getSvelteConfigAliases(cwd) {
|
|
1722
1726
|
const aliases = {};
|
|
1723
1727
|
const configPaths = [
|
|
1724
|
-
|
|
1725
|
-
|
|
1728
|
+
path__default.join(cwd, "svelte.config.js"),
|
|
1729
|
+
path__default.join(cwd, "svelte.config.ts")
|
|
1726
1730
|
];
|
|
1727
1731
|
for (const configPath of configPaths) {
|
|
1728
|
-
if (
|
|
1732
|
+
if (fs__default.existsSync(configPath)) {
|
|
1729
1733
|
try {
|
|
1730
|
-
const content =
|
|
1734
|
+
const content = fs__default.readFileSync(configPath, "utf-8");
|
|
1731
1735
|
const aliasMatch = content.match(/alias\s*:\s*\{([^}]+)\}/);
|
|
1732
1736
|
if (aliasMatch && aliasMatch[1]) {
|
|
1733
1737
|
const aliasContent = aliasMatch[1];
|
|
@@ -1737,8 +1741,8 @@ function getSvelteConfigAliases(cwd) {
|
|
|
1737
1741
|
for (const match of aliasMatches) {
|
|
1738
1742
|
const [, alias, target] = match;
|
|
1739
1743
|
if (alias && target) {
|
|
1740
|
-
aliases[alias + "/*"] =
|
|
1741
|
-
aliases[alias] =
|
|
1744
|
+
aliases[alias + "/*"] = path__default.resolve(cwd, target) + "/*";
|
|
1745
|
+
aliases[alias] = path__default.resolve(cwd, target);
|
|
1742
1746
|
}
|
|
1743
1747
|
}
|
|
1744
1748
|
}
|
|
@@ -1859,27 +1863,27 @@ possiblePaths = [
|
|
|
1859
1863
|
...possiblePaths.map((it) => `app/${it}`)
|
|
1860
1864
|
];
|
|
1861
1865
|
function resolveReferencePath(configDir, refPath) {
|
|
1862
|
-
const resolvedPath =
|
|
1866
|
+
const resolvedPath = path__default.resolve(configDir, refPath);
|
|
1863
1867
|
if (refPath.endsWith(".json")) {
|
|
1864
1868
|
return resolvedPath;
|
|
1865
1869
|
}
|
|
1866
|
-
if (
|
|
1870
|
+
if (fs__default.existsSync(resolvedPath)) {
|
|
1867
1871
|
try {
|
|
1868
|
-
const stats =
|
|
1872
|
+
const stats = fs__default.statSync(resolvedPath);
|
|
1869
1873
|
if (stats.isFile()) {
|
|
1870
1874
|
return resolvedPath;
|
|
1871
1875
|
}
|
|
1872
1876
|
} catch {
|
|
1873
1877
|
}
|
|
1874
1878
|
}
|
|
1875
|
-
return
|
|
1879
|
+
return path__default.resolve(configDir, refPath, "tsconfig.json");
|
|
1876
1880
|
}
|
|
1877
1881
|
function getPathAliasesRecursive(tsconfigPath, visited = /* @__PURE__ */ new Set()) {
|
|
1878
1882
|
if (visited.has(tsconfigPath)) {
|
|
1879
1883
|
return {};
|
|
1880
1884
|
}
|
|
1881
1885
|
visited.add(tsconfigPath);
|
|
1882
|
-
if (!
|
|
1886
|
+
if (!fs__default.existsSync(tsconfigPath)) {
|
|
1883
1887
|
logger.warn(`Referenced tsconfig not found: ${tsconfigPath}`);
|
|
1884
1888
|
return {};
|
|
1885
1889
|
}
|
|
@@ -1887,14 +1891,14 @@ function getPathAliasesRecursive(tsconfigPath, visited = /* @__PURE__ */ new Set
|
|
|
1887
1891
|
const tsConfig = getTsconfigInfo(void 0, tsconfigPath);
|
|
1888
1892
|
const { paths = {}, baseUrl = "." } = tsConfig.compilerOptions || {};
|
|
1889
1893
|
const result = {};
|
|
1890
|
-
const configDir =
|
|
1894
|
+
const configDir = path__default.dirname(tsconfigPath);
|
|
1891
1895
|
const obj = Object.entries(paths);
|
|
1892
1896
|
for (const [alias, aliasPaths] of obj) {
|
|
1893
1897
|
for (const aliasedPath of aliasPaths) {
|
|
1894
|
-
const resolvedBaseUrl =
|
|
1898
|
+
const resolvedBaseUrl = path__default.resolve(configDir, baseUrl);
|
|
1895
1899
|
const finalAlias = alias.slice(-1) === "*" ? alias.slice(0, -1) : alias;
|
|
1896
1900
|
const finalAliasedPath = aliasedPath.slice(-1) === "*" ? aliasedPath.slice(0, -1) : aliasedPath;
|
|
1897
|
-
result[finalAlias || ""] =
|
|
1901
|
+
result[finalAlias || ""] = path__default.join(resolvedBaseUrl, finalAliasedPath);
|
|
1898
1902
|
}
|
|
1899
1903
|
}
|
|
1900
1904
|
if (tsConfig.references) {
|
|
@@ -1915,8 +1919,8 @@ function getPathAliasesRecursive(tsconfigPath, visited = /* @__PURE__ */ new Set
|
|
|
1915
1919
|
}
|
|
1916
1920
|
}
|
|
1917
1921
|
function getPathAliases(cwd) {
|
|
1918
|
-
const tsConfigPath =
|
|
1919
|
-
if (!
|
|
1922
|
+
const tsConfigPath = path__default.join(cwd, "tsconfig.json");
|
|
1923
|
+
if (!fs__default.existsSync(tsConfigPath)) {
|
|
1920
1924
|
return null;
|
|
1921
1925
|
}
|
|
1922
1926
|
try {
|
|
@@ -1960,7 +1964,7 @@ async function getConfig({
|
|
|
1960
1964
|
try {
|
|
1961
1965
|
let configFile = null;
|
|
1962
1966
|
if (configPath) {
|
|
1963
|
-
let resolvedPath =
|
|
1967
|
+
let resolvedPath = path__default.join(cwd, configPath);
|
|
1964
1968
|
if (existsSync(configPath)) resolvedPath = configPath;
|
|
1965
1969
|
const { config } = await loadConfig({
|
|
1966
1970
|
configFile: resolvedPath,
|
|
@@ -2057,7 +2061,7 @@ async function migrateAction(opts) {
|
|
|
2057
2061
|
y: z.boolean().optional(),
|
|
2058
2062
|
yes: z.boolean().optional()
|
|
2059
2063
|
}).parse(opts);
|
|
2060
|
-
const cwd =
|
|
2064
|
+
const cwd = path__default.resolve(options.cwd);
|
|
2061
2065
|
if (!existsSync(cwd)) {
|
|
2062
2066
|
logger.error(`The directory "${cwd}" does not exist.`);
|
|
2063
2067
|
process.exit(1);
|
|
@@ -2277,9 +2281,9 @@ const generateDrizzleSchema = async ({
|
|
|
2277
2281
|
mysql: field.bigint ? `bigint('${name}', { mode: 'number' })` : `int('${name}')`
|
|
2278
2282
|
},
|
|
2279
2283
|
date: {
|
|
2280
|
-
sqlite: `integer('${name}', { mode: '
|
|
2284
|
+
sqlite: `integer('${name}', { mode: 'timestamp_ms' })`,
|
|
2281
2285
|
pg: `timestamp('${name}')`,
|
|
2282
|
-
mysql: `timestamp('${name}')`
|
|
2286
|
+
mysql: `timestamp('${name}', { fsp: 3 })`
|
|
2283
2287
|
},
|
|
2284
2288
|
"number[]": {
|
|
2285
2289
|
sqlite: `integer('${name}').array()`,
|
|
@@ -2307,7 +2311,7 @@ const generateDrizzleSchema = async ({
|
|
|
2307
2311
|
if (databaseType === "pg") {
|
|
2308
2312
|
id = `serial("id").primaryKey()`;
|
|
2309
2313
|
} else if (databaseType === "sqlite") {
|
|
2310
|
-
id = `
|
|
2314
|
+
id = `integer("id", { mode: "number" }).primaryKey({ autoIncrement: true })`;
|
|
2311
2315
|
} else {
|
|
2312
2316
|
id = `int("id").autoincrement().primaryKey()`;
|
|
2313
2317
|
}
|
|
@@ -2327,12 +2331,13 @@ const generateDrizzleSchema = async ({
|
|
|
2327
2331
|
id: ${id},
|
|
2328
2332
|
${Object.keys(fields).map((field) => {
|
|
2329
2333
|
const attr = fields[field];
|
|
2330
|
-
|
|
2334
|
+
const fieldName = attr.fieldName || field;
|
|
2335
|
+
let type = getType(fieldName, attr);
|
|
2331
2336
|
if (attr.defaultValue !== null && typeof attr.defaultValue !== "undefined") {
|
|
2332
2337
|
if (typeof attr.defaultValue === "function") {
|
|
2333
2338
|
if (attr.type === "date" && attr.defaultValue.toString().includes("new Date()")) {
|
|
2334
2339
|
if (databaseType === "sqlite") {
|
|
2335
|
-
type += `.default(sql\`(
|
|
2340
|
+
type += `.default(sql\`(cast(unixepoch('subsecond') * 1000 as integer))\`)`;
|
|
2336
2341
|
} else {
|
|
2337
2342
|
type += `.defaultNow()`;
|
|
2338
2343
|
}
|
|
@@ -2350,10 +2355,10 @@ const generateDrizzleSchema = async ({
|
|
|
2350
2355
|
type += `.$onUpdate(${attr.onUpdate})`;
|
|
2351
2356
|
}
|
|
2352
2357
|
}
|
|
2353
|
-
return `${
|
|
2358
|
+
return `${fieldName}: ${type}${attr.required ? ".notNull()" : ""}${attr.unique ? ".unique()" : ""}${attr.references ? `.references(()=> ${getModelName(
|
|
2354
2359
|
tables[attr.references.model]?.modelName || attr.references.model,
|
|
2355
2360
|
adapter.options
|
|
2356
|
-
)}.${attr.references.field}, { onDelete: '${attr.references.onDelete || "cascade"}' })` : ""}`;
|
|
2361
|
+
)}.${fields[attr.references.field]?.fieldName || attr.references.field}, { onDelete: '${attr.references.onDelete || "cascade"}' })` : ""}`;
|
|
2357
2362
|
}).join(",\n ")}
|
|
2358
2363
|
});`;
|
|
2359
2364
|
code += `
|
|
@@ -2451,11 +2456,11 @@ const generatePrismaSchema = async ({
|
|
|
2451
2456
|
const provider = adapter.options?.provider || "postgresql";
|
|
2452
2457
|
const tables = getAuthTables(options);
|
|
2453
2458
|
const filePath = file || "./prisma/schema.prisma";
|
|
2454
|
-
const schemaPrismaExist = existsSync(
|
|
2459
|
+
const schemaPrismaExist = existsSync(path__default.join(process.cwd(), filePath));
|
|
2455
2460
|
let schemaPrisma = "";
|
|
2456
2461
|
if (schemaPrismaExist) {
|
|
2457
2462
|
schemaPrisma = await fs$1.readFile(
|
|
2458
|
-
|
|
2463
|
+
path__default.join(process.cwd(), filePath),
|
|
2459
2464
|
"utf-8"
|
|
2460
2465
|
);
|
|
2461
2466
|
} else {
|
|
@@ -2525,10 +2530,7 @@ const generatePrismaSchema = async ({
|
|
|
2525
2530
|
builder.model(modelName).field("id", "String").attribute("id").attribute(`map("_id")`);
|
|
2526
2531
|
} else {
|
|
2527
2532
|
if (options.advanced?.database?.useNumberId) {
|
|
2528
|
-
|
|
2529
|
-
if (provider !== "sqlite") {
|
|
2530
|
-
col.attribute("default(autoincrement())");
|
|
2531
|
-
}
|
|
2533
|
+
builder.model(modelName).field("id", "Int").attribute("id").attribute("default(autoincrement())");
|
|
2532
2534
|
} else {
|
|
2533
2535
|
builder.model(modelName).field("id", "String").attribute("id");
|
|
2534
2536
|
}
|
|
@@ -2563,8 +2565,6 @@ const generatePrismaSchema = async ({
|
|
|
2563
2565
|
if (provider === "mongodb") {
|
|
2564
2566
|
fieldBuilder.attribute(`map("_id")`);
|
|
2565
2567
|
}
|
|
2566
|
-
} else if (fieldName !== field) {
|
|
2567
|
-
fieldBuilder.attribute(`map("${field}")`);
|
|
2568
2568
|
}
|
|
2569
2569
|
if (attr.unique) {
|
|
2570
2570
|
builder.model(modelName).blockAttribute(`unique([${fieldName}])`);
|
|
@@ -2697,7 +2697,7 @@ async function generateAction(opts) {
|
|
|
2697
2697
|
y: z.boolean().optional(),
|
|
2698
2698
|
yes: z.boolean().optional()
|
|
2699
2699
|
}).parse(opts);
|
|
2700
|
-
const cwd =
|
|
2700
|
+
const cwd = path__default.resolve(options.cwd);
|
|
2701
2701
|
if (!existsSync(cwd)) {
|
|
2702
2702
|
logger.error(`The directory "${cwd}" does not exist.`);
|
|
2703
2703
|
process.exit(1);
|
|
@@ -2754,16 +2754,16 @@ async function generateAction(opts) {
|
|
|
2754
2754
|
confirm2 = response.confirm;
|
|
2755
2755
|
}
|
|
2756
2756
|
if (confirm2) {
|
|
2757
|
-
const exist = existsSync(
|
|
2757
|
+
const exist = existsSync(path__default.join(cwd, schema.fileName));
|
|
2758
2758
|
if (!exist) {
|
|
2759
|
-
await fs$1.mkdir(
|
|
2759
|
+
await fs$1.mkdir(path__default.dirname(path__default.join(cwd, schema.fileName)), {
|
|
2760
2760
|
recursive: true
|
|
2761
2761
|
});
|
|
2762
2762
|
}
|
|
2763
2763
|
if (schema.overwrite) {
|
|
2764
|
-
await fs$1.writeFile(
|
|
2764
|
+
await fs$1.writeFile(path__default.join(cwd, schema.fileName), schema.code);
|
|
2765
2765
|
} else {
|
|
2766
|
-
await fs$1.appendFile(
|
|
2766
|
+
await fs$1.appendFile(path__default.join(cwd, schema.fileName), schema.code);
|
|
2767
2767
|
}
|
|
2768
2768
|
logger.success(
|
|
2769
2769
|
`\u{1F680} Schema was ${schema.overwrite ? "overwritten" : "appended"} successfully!`
|
|
@@ -2824,15 +2824,15 @@ async function generateAction(opts) {
|
|
|
2824
2824
|
process.exit(1);
|
|
2825
2825
|
}
|
|
2826
2826
|
if (!options.output) {
|
|
2827
|
-
const dirExist = existsSync(
|
|
2827
|
+
const dirExist = existsSync(path__default.dirname(path__default.join(cwd, schema.fileName)));
|
|
2828
2828
|
if (!dirExist) {
|
|
2829
|
-
await fs$1.mkdir(
|
|
2829
|
+
await fs$1.mkdir(path__default.dirname(path__default.join(cwd, schema.fileName)), {
|
|
2830
2830
|
recursive: true
|
|
2831
2831
|
});
|
|
2832
2832
|
}
|
|
2833
2833
|
}
|
|
2834
2834
|
await fs$1.writeFile(
|
|
2835
|
-
options.output ||
|
|
2835
|
+
options.output || path__default.join(cwd, schema.fileName),
|
|
2836
2836
|
schema.code
|
|
2837
2837
|
);
|
|
2838
2838
|
logger.success(`\u{1F680} Schema was generated successfully!`);
|
|
@@ -2857,8 +2857,8 @@ const generate = new Command("generate").option(
|
|
|
2857
2857
|
|
|
2858
2858
|
const DEMO_URL = "https://demo.better-auth.com";
|
|
2859
2859
|
const CLIENT_ID = "better-auth-cli";
|
|
2860
|
-
const CONFIG_DIR =
|
|
2861
|
-
const TOKEN_FILE =
|
|
2860
|
+
const CONFIG_DIR = path__default.join(os__default.homedir(), ".better-auth");
|
|
2861
|
+
const TOKEN_FILE = path__default.join(CONFIG_DIR, "token.json");
|
|
2862
2862
|
async function loginAction(opts) {
|
|
2863
2863
|
const options = z.object({
|
|
2864
2864
|
serverUrl: z.string().optional(),
|
|
@@ -3063,13 +3063,13 @@ const login = new Command("login").description(
|
|
|
3063
3063
|
).option("--server-url <url>", "The Better Auth server URL", DEMO_URL).option("--client-id <id>", "The OAuth client ID", CLIENT_ID).action(loginAction);
|
|
3064
3064
|
|
|
3065
3065
|
function getSystemInfo() {
|
|
3066
|
-
const platform =
|
|
3067
|
-
const arch =
|
|
3068
|
-
const version =
|
|
3069
|
-
const release =
|
|
3070
|
-
const cpus =
|
|
3071
|
-
const memory =
|
|
3072
|
-
const freeMemory =
|
|
3066
|
+
const platform = os__default.platform();
|
|
3067
|
+
const arch = os__default.arch();
|
|
3068
|
+
const version = os__default.version();
|
|
3069
|
+
const release = os__default.release();
|
|
3070
|
+
const cpus = os__default.cpus();
|
|
3071
|
+
const memory = os__default.totalmem();
|
|
3072
|
+
const freeMemory = os__default.freemem();
|
|
3073
3073
|
return {
|
|
3074
3074
|
platform,
|
|
3075
3075
|
arch,
|
|
@@ -3109,7 +3109,7 @@ function getVersion(command) {
|
|
|
3109
3109
|
}
|
|
3110
3110
|
}
|
|
3111
3111
|
function getFrameworkInfo(projectRoot) {
|
|
3112
|
-
const packageJsonPath =
|
|
3112
|
+
const packageJsonPath = path__default.join(projectRoot, "package.json");
|
|
3113
3113
|
if (!existsSync(packageJsonPath)) {
|
|
3114
3114
|
return null;
|
|
3115
3115
|
}
|
|
@@ -3141,7 +3141,7 @@ function getFrameworkInfo(projectRoot) {
|
|
|
3141
3141
|
}
|
|
3142
3142
|
}
|
|
3143
3143
|
function getDatabaseInfo(projectRoot) {
|
|
3144
|
-
const packageJsonPath =
|
|
3144
|
+
const packageJsonPath = path__default.join(projectRoot, "package.json");
|
|
3145
3145
|
if (!existsSync(packageJsonPath)) {
|
|
3146
3146
|
return null;
|
|
3147
3147
|
}
|
|
@@ -3366,7 +3366,7 @@ ${formatOutput(value, indent + 2)}`;
|
|
|
3366
3366
|
return `${spaces}${JSON.stringify(data)}`;
|
|
3367
3367
|
}
|
|
3368
3368
|
const info = new Command("info").description("Display system and Better Auth configuration information").option("--cwd <cwd>", "The working directory", process.cwd()).option("--config <config>", "Path to the Better Auth configuration file").option("-j, --json", "Output as JSON").option("-c, --copy", "Copy output to clipboard (requires pbcopy/xclip)").action(async (options) => {
|
|
3369
|
-
const projectRoot =
|
|
3369
|
+
const projectRoot = path__default.resolve(options.cwd || process.cwd());
|
|
3370
3370
|
const systemInfo = getSystemInfo();
|
|
3371
3371
|
const nodeInfo = getNodeInfo();
|
|
3372
3372
|
const packageManager = getPackageManager();
|
|
@@ -3390,7 +3390,7 @@ const info = new Command("info").description("Display system and Better Auth con
|
|
|
3390
3390
|
console.log(jsonOutput);
|
|
3391
3391
|
if (options.copy) {
|
|
3392
3392
|
try {
|
|
3393
|
-
const platform =
|
|
3393
|
+
const platform = os__default.platform();
|
|
3394
3394
|
if (platform === "darwin") {
|
|
3395
3395
|
execSync("pbcopy", { input: jsonOutput });
|
|
3396
3396
|
console.log(chalk.green("\n\u2713 Copied to clipboard"));
|
|
@@ -3463,7 +3463,7 @@ Better Auth:
|
|
|
3463
3463
|
${JSON.stringify(betterAuthInfo, null, 2)}
|
|
3464
3464
|
`;
|
|
3465
3465
|
try {
|
|
3466
|
-
const platform =
|
|
3466
|
+
const platform = os__default.platform();
|
|
3467
3467
|
if (platform === "darwin") {
|
|
3468
3468
|
execSync("pbcopy", { input: textOutput });
|
|
3469
3469
|
console.log(chalk.green("\u2713 Copied to clipboard"));
|
|
@@ -3480,6 +3480,197 @@ ${JSON.stringify(betterAuthInfo, null, 2)}
|
|
|
3480
3480
|
}
|
|
3481
3481
|
});
|
|
3482
3482
|
|
|
3483
|
+
async function mcpAction(options) {
|
|
3484
|
+
const mcpUrl = "https://mcp.chonkie.ai/better-auth/better-auth-builder/mcp";
|
|
3485
|
+
const mcpName = "Better Auth";
|
|
3486
|
+
if (options.cursor) {
|
|
3487
|
+
await handleCursorAction(mcpUrl, mcpName);
|
|
3488
|
+
} else if (options.claudeCode) {
|
|
3489
|
+
handleClaudeCodeAction(mcpUrl);
|
|
3490
|
+
} else if (options.openCode) {
|
|
3491
|
+
handleOpenCodeAction(mcpUrl);
|
|
3492
|
+
} else if (options.manual) {
|
|
3493
|
+
handleManualAction(mcpUrl, mcpName);
|
|
3494
|
+
} else {
|
|
3495
|
+
showAllOptions();
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
async function handleCursorAction(mcpUrl, mcpName) {
|
|
3499
|
+
const mcpConfig = {
|
|
3500
|
+
url: mcpUrl
|
|
3501
|
+
};
|
|
3502
|
+
const encodedConfig = base64.encode(
|
|
3503
|
+
new TextEncoder().encode(JSON.stringify(mcpConfig))
|
|
3504
|
+
);
|
|
3505
|
+
const deeplinkUrl = `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(mcpName)}&config=${encodedConfig}`;
|
|
3506
|
+
console.log(chalk.bold.blue("\u{1F680} Adding Better Auth MCP to Cursor..."));
|
|
3507
|
+
try {
|
|
3508
|
+
const platform = os.platform();
|
|
3509
|
+
let command;
|
|
3510
|
+
switch (platform) {
|
|
3511
|
+
case "darwin":
|
|
3512
|
+
command = `open "${deeplinkUrl}"`;
|
|
3513
|
+
break;
|
|
3514
|
+
case "win32":
|
|
3515
|
+
command = `start "" "${deeplinkUrl}"`;
|
|
3516
|
+
break;
|
|
3517
|
+
case "linux":
|
|
3518
|
+
command = `xdg-open "${deeplinkUrl}"`;
|
|
3519
|
+
break;
|
|
3520
|
+
default:
|
|
3521
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
3522
|
+
}
|
|
3523
|
+
execSync(command, { stdio: "inherit" });
|
|
3524
|
+
console.log(chalk.green("\n\u2713 Cursor MCP installed successfully!"));
|
|
3525
|
+
} catch (error) {
|
|
3526
|
+
console.log(
|
|
3527
|
+
chalk.yellow(
|
|
3528
|
+
"\n\u26A0 Could not automatically open Cursor. Please copy the deeplink URL above and open it manually."
|
|
3529
|
+
)
|
|
3530
|
+
);
|
|
3531
|
+
console.log(
|
|
3532
|
+
chalk.gray(
|
|
3533
|
+
"\nYou can also manually add this configuration to your Cursor MCP settings:"
|
|
3534
|
+
)
|
|
3535
|
+
);
|
|
3536
|
+
console.log(chalk.gray(JSON.stringify(mcpConfig, null, 2)));
|
|
3537
|
+
}
|
|
3538
|
+
console.log(chalk.bold.white("\n\u2728 Next Steps:"));
|
|
3539
|
+
console.log(
|
|
3540
|
+
chalk.gray("\u2022 The MCP server will be added to your Cursor configuration")
|
|
3541
|
+
);
|
|
3542
|
+
console.log(
|
|
3543
|
+
chalk.gray("\u2022 You can now use Better Auth features directly in Cursor")
|
|
3544
|
+
);
|
|
3545
|
+
}
|
|
3546
|
+
function handleClaudeCodeAction(mcpUrl) {
|
|
3547
|
+
console.log(chalk.bold.blue("\u{1F916} Adding Better Auth MCP to Claude Code..."));
|
|
3548
|
+
const command = `claude mcp add --transport http better-auth ${mcpUrl}`;
|
|
3549
|
+
try {
|
|
3550
|
+
execSync(command, { stdio: "inherit" });
|
|
3551
|
+
console.log(chalk.green("\n\u2713 Claude Code MCP installed successfully!"));
|
|
3552
|
+
} catch (error) {
|
|
3553
|
+
console.log(
|
|
3554
|
+
chalk.yellow(
|
|
3555
|
+
"\n\u26A0 Could not automatically add to Claude Code. Please run this command manually:"
|
|
3556
|
+
)
|
|
3557
|
+
);
|
|
3558
|
+
console.log(chalk.cyan(command));
|
|
3559
|
+
}
|
|
3560
|
+
console.log(chalk.bold.white("\n\u2728 Next Steps:"));
|
|
3561
|
+
console.log(
|
|
3562
|
+
chalk.gray(
|
|
3563
|
+
"\u2022 The MCP server will be added to your Claude Code configuration"
|
|
3564
|
+
)
|
|
3565
|
+
);
|
|
3566
|
+
console.log(
|
|
3567
|
+
chalk.gray(
|
|
3568
|
+
"\u2022 You can now use Better Auth features directly in Claude Code"
|
|
3569
|
+
)
|
|
3570
|
+
);
|
|
3571
|
+
}
|
|
3572
|
+
function handleOpenCodeAction(mcpUrl) {
|
|
3573
|
+
console.log(chalk.bold.blue("\u{1F527} Adding Better Auth MCP to Open Code..."));
|
|
3574
|
+
const openCodeConfig = {
|
|
3575
|
+
$schema: "https://opencode.ai/config.json",
|
|
3576
|
+
mcp: {
|
|
3577
|
+
"Better Auth": {
|
|
3578
|
+
type: "remote",
|
|
3579
|
+
url: mcpUrl,
|
|
3580
|
+
enabled: true
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
};
|
|
3584
|
+
const configPath = path.join(process.cwd(), "opencode.json");
|
|
3585
|
+
try {
|
|
3586
|
+
let existingConfig = {};
|
|
3587
|
+
if (fs.existsSync(configPath)) {
|
|
3588
|
+
const existingContent = fs.readFileSync(configPath, "utf8");
|
|
3589
|
+
existingConfig = JSON.parse(existingContent);
|
|
3590
|
+
}
|
|
3591
|
+
const mergedConfig = {
|
|
3592
|
+
...existingConfig,
|
|
3593
|
+
...openCodeConfig,
|
|
3594
|
+
mcp: {
|
|
3595
|
+
...existingConfig.mcp,
|
|
3596
|
+
...openCodeConfig.mcp
|
|
3597
|
+
}
|
|
3598
|
+
};
|
|
3599
|
+
fs.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2));
|
|
3600
|
+
console.log(
|
|
3601
|
+
chalk.green(`
|
|
3602
|
+
\u2713 Open Code configuration written to ${configPath}`)
|
|
3603
|
+
);
|
|
3604
|
+
console.log(chalk.green("\u2713 Better Auth MCP added successfully!"));
|
|
3605
|
+
} catch (error) {
|
|
3606
|
+
console.log(
|
|
3607
|
+
chalk.yellow(
|
|
3608
|
+
"\n\u26A0 Could not automatically write opencode.json. Please add this configuration manually:"
|
|
3609
|
+
)
|
|
3610
|
+
);
|
|
3611
|
+
console.log(chalk.cyan(JSON.stringify(openCodeConfig, null, 2)));
|
|
3612
|
+
}
|
|
3613
|
+
console.log(chalk.bold.white("\n\u2728 Next Steps:"));
|
|
3614
|
+
console.log(chalk.gray("\u2022 Restart Open Code to load the new MCP server"));
|
|
3615
|
+
console.log(
|
|
3616
|
+
chalk.gray("\u2022 You can now use Better Auth features directly in Open Code")
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
function handleManualAction(mcpUrl, mcpName) {
|
|
3620
|
+
console.log(chalk.bold.blue("\u{1F4DD} Adding Better Auth MCP Configuration..."));
|
|
3621
|
+
const manualConfig = {
|
|
3622
|
+
[mcpName]: {
|
|
3623
|
+
url: mcpUrl
|
|
3624
|
+
}
|
|
3625
|
+
};
|
|
3626
|
+
const configPath = path.join(process.cwd(), "mcp.json");
|
|
3627
|
+
try {
|
|
3628
|
+
let existingConfig = {};
|
|
3629
|
+
if (fs.existsSync(configPath)) {
|
|
3630
|
+
const existingContent = fs.readFileSync(configPath, "utf8");
|
|
3631
|
+
existingConfig = JSON.parse(existingContent);
|
|
3632
|
+
}
|
|
3633
|
+
const mergedConfig = {
|
|
3634
|
+
...existingConfig,
|
|
3635
|
+
...manualConfig
|
|
3636
|
+
};
|
|
3637
|
+
fs.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2));
|
|
3638
|
+
console.log(chalk.green(`
|
|
3639
|
+
\u2713 MCP configuration written to ${configPath}`));
|
|
3640
|
+
console.log(chalk.green("\u2713 Better Auth MCP added successfully!"));
|
|
3641
|
+
} catch (error) {
|
|
3642
|
+
console.log(
|
|
3643
|
+
chalk.yellow(
|
|
3644
|
+
"\n\u26A0 Could not automatically write mcp.json. Please add this configuration manually:"
|
|
3645
|
+
)
|
|
3646
|
+
);
|
|
3647
|
+
console.log(chalk.cyan(JSON.stringify(manualConfig, null, 2)));
|
|
3648
|
+
}
|
|
3649
|
+
console.log(chalk.bold.white("\n\u2728 Next Steps:"));
|
|
3650
|
+
console.log(chalk.gray("\u2022 Restart your MCP client to load the new server"));
|
|
3651
|
+
console.log(
|
|
3652
|
+
chalk.gray(
|
|
3653
|
+
"\u2022 You can now use Better Auth features directly in your MCP client"
|
|
3654
|
+
)
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
function showAllOptions(mcpUrl, mcpName) {
|
|
3658
|
+
console.log(chalk.bold.blue("\u{1F50C} Better Auth MCP Server"));
|
|
3659
|
+
console.log(chalk.gray("Choose your MCP client to get started:"));
|
|
3660
|
+
console.log();
|
|
3661
|
+
console.log(chalk.bold.white("Available Commands:"));
|
|
3662
|
+
console.log(chalk.cyan(" --cursor ") + chalk.gray("Add to Cursor"));
|
|
3663
|
+
console.log(
|
|
3664
|
+
chalk.cyan(" --claude-code ") + chalk.gray("Add to Claude Code")
|
|
3665
|
+
);
|
|
3666
|
+
console.log(chalk.cyan(" --open-code ") + chalk.gray("Add to Open Code"));
|
|
3667
|
+
console.log(
|
|
3668
|
+
chalk.cyan(" --manual ") + chalk.gray("Manual configuration")
|
|
3669
|
+
);
|
|
3670
|
+
console.log();
|
|
3671
|
+
}
|
|
3672
|
+
const mcp = new Command("mcp").description("Add Better Auth MCP server to MCP Clients").option("--cursor", "Automatically open Cursor with the MCP configuration").option("--claude-code", "Show Claude Code MCP configuration command").option("--open-code", "Show Open Code MCP configuration").option("--manual", "Show manual MCP configuration for mcp.json").action(mcpAction);
|
|
3673
|
+
|
|
3483
3674
|
process.on("SIGINT", () => process.exit(0));
|
|
3484
3675
|
process.on("SIGTERM", () => process.exit(0));
|
|
3485
3676
|
async function main() {
|
|
@@ -3489,7 +3680,7 @@ async function main() {
|
|
|
3489
3680
|
packageInfo = await getPackageInfo();
|
|
3490
3681
|
} catch (error) {
|
|
3491
3682
|
}
|
|
3492
|
-
program.addCommand(init).addCommand(migrate).addCommand(generate).addCommand(generateSecret).addCommand(info).addCommand(login).version(packageInfo.version || "1.1.2").description("Better Auth CLI").action(() => program.help());
|
|
3683
|
+
program.addCommand(init).addCommand(migrate).addCommand(generate).addCommand(generateSecret).addCommand(info).addCommand(login).addCommand(mcp).version(packageInfo.version || "1.1.2").description("Better Auth CLI").action(() => program.help());
|
|
3493
3684
|
program.parse();
|
|
3494
3685
|
}
|
|
3495
3686
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/cli",
|
|
3
|
-
"version": "1.4.0-beta.
|
|
3
|
+
"version": "1.4.0-beta.7",
|
|
4
4
|
"description": "The CLI for Better Auth",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"repository": {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@babel/core": "^7.28.4",
|
|
36
36
|
"@babel/preset-react": "^7.27.1",
|
|
37
37
|
"@babel/preset-typescript": "^7.27.1",
|
|
38
|
+
"@better-auth/utils": "0.3.0",
|
|
38
39
|
"@clack/prompts": "^0.11.0",
|
|
39
40
|
"@mrleebo/prisma-ast": "^0.13.0",
|
|
40
41
|
"@prisma/client": "^5.22.0",
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"tinyexec": "^0.3.2",
|
|
57
58
|
"yocto-spinner": "^0.2.3",
|
|
58
59
|
"zod": "^4.1.5",
|
|
59
|
-
"better-auth": "1.4.0-beta.
|
|
60
|
+
"better-auth": "1.4.0-beta.7"
|
|
60
61
|
},
|
|
61
62
|
"files": [
|
|
62
63
|
"dist"
|