@better-auth/cli 1.4.0-beta.6 → 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.
Files changed (2) hide show
  1. package/dist/index.mjs +271 -76
  2. 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 fs, { existsSync, readFileSync } from 'fs';
8
- import path from 'path';
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 ? path.join(cwd, "package.json") : path.join("package.json");
30
- return JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
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 ? path.join(cwd, "tsconfig.json") : path.join("tsconfig.json");
685
+ tsConfigPath = cwd ? path__default.join(cwd, "tsconfig.json") : path__default.join("tsconfig.json");
682
686
  }
683
687
  try {
684
- const text = fs.readFileSync(tsConfigPath, "utf-8");
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 = path.resolve(options.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 ? path.resolve(cwd, options.tsconfig) : path.join(cwd, "tsconfig.json");
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
- path.join(cwd, "tsconfig.json"),
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 = path.join(cwd, options.config);
1164
+ config_path = path__default.join(cwd, options.config);
1161
1165
  } else {
1162
1166
  for (const possiblePath of possiblePaths) {
1163
- const doesExist = existsSync(path.join(cwd, possiblePath));
1167
+ const doesExist = existsSync(path__default.join(cwd, possiblePath));
1164
1168
  if (doesExist) {
1165
- config_path = path.join(cwd, possiblePath);
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(path.join(cwd, possible_next_config_path))) {
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 = path.join(cwd, "auth.ts");
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: path.join(cwd, x),
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(path.join(cwd, possiblePath));
1404
+ const doesExist = existsSync(path__default.join(cwd, possiblePath));
1401
1405
  if (doesExist) {
1402
- authClientConfigPath = path.join(cwd, possiblePath);
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 = path.join(cwd, "auth-client.ts");
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: ("./" + path.join(config_path.replace(cwd, ""))).replace(".//", "./"),
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
- path.join(cwd, targetEnvFile),
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: [path.join(cwd, targetEnvFile)],
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: path.join(cwd, x),
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 = path.join(cwd, "package.json");
1682
- const svelteConfigPath = path.join(cwd, "svelte.config.js");
1683
- const svelteConfigTsPath = path.join(cwd, "svelte.config.ts");
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 (fs.existsSync(packageJsonPath)) {
1689
+ if (fs__default.existsSync(packageJsonPath)) {
1686
1690
  try {
1687
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
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 = fs.existsSync(svelteConfigPath) || fs.existsSync(svelteConfigTsPath);
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 = [path.join(cwd, "src", "lib"), path.join(cwd, "lib")];
1706
+ const libPaths = [path__default.join(cwd, "src", "lib"), path__default.join(cwd, "lib")];
1703
1707
  for (const libPath of libPaths) {
1704
- if (fs.existsSync(libPath)) {
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 = path.join(libPath, subPath);
1709
- if (fs.existsSync(subDir)) {
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
- path.join(cwd, "svelte.config.js"),
1725
- path.join(cwd, "svelte.config.ts")
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 (fs.existsSync(configPath)) {
1732
+ if (fs__default.existsSync(configPath)) {
1729
1733
  try {
1730
- const content = fs.readFileSync(configPath, "utf-8");
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 + "/*"] = path.resolve(cwd, target) + "/*";
1741
- aliases[alias] = path.resolve(cwd, target);
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 = path.resolve(configDir, refPath);
1866
+ const resolvedPath = path__default.resolve(configDir, refPath);
1863
1867
  if (refPath.endsWith(".json")) {
1864
1868
  return resolvedPath;
1865
1869
  }
1866
- if (fs.existsSync(resolvedPath)) {
1870
+ if (fs__default.existsSync(resolvedPath)) {
1867
1871
  try {
1868
- const stats = fs.statSync(resolvedPath);
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 path.resolve(configDir, refPath, "tsconfig.json");
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 (!fs.existsSync(tsconfigPath)) {
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 = path.dirname(tsconfigPath);
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 = path.resolve(configDir, baseUrl);
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 || ""] = path.join(resolvedBaseUrl, finalAliasedPath);
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 = path.join(cwd, "tsconfig.json");
1919
- if (!fs.existsSync(tsConfigPath)) {
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 = path.join(cwd, configPath);
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 = path.resolve(options.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);
@@ -2452,11 +2456,11 @@ const generatePrismaSchema = async ({
2452
2456
  const provider = adapter.options?.provider || "postgresql";
2453
2457
  const tables = getAuthTables(options);
2454
2458
  const filePath = file || "./prisma/schema.prisma";
2455
- const schemaPrismaExist = existsSync(path.join(process.cwd(), filePath));
2459
+ const schemaPrismaExist = existsSync(path__default.join(process.cwd(), filePath));
2456
2460
  let schemaPrisma = "";
2457
2461
  if (schemaPrismaExist) {
2458
2462
  schemaPrisma = await fs$1.readFile(
2459
- path.join(process.cwd(), filePath),
2463
+ path__default.join(process.cwd(), filePath),
2460
2464
  "utf-8"
2461
2465
  );
2462
2466
  } else {
@@ -2693,7 +2697,7 @@ async function generateAction(opts) {
2693
2697
  y: z.boolean().optional(),
2694
2698
  yes: z.boolean().optional()
2695
2699
  }).parse(opts);
2696
- const cwd = path.resolve(options.cwd);
2700
+ const cwd = path__default.resolve(options.cwd);
2697
2701
  if (!existsSync(cwd)) {
2698
2702
  logger.error(`The directory "${cwd}" does not exist.`);
2699
2703
  process.exit(1);
@@ -2750,16 +2754,16 @@ async function generateAction(opts) {
2750
2754
  confirm2 = response.confirm;
2751
2755
  }
2752
2756
  if (confirm2) {
2753
- const exist = existsSync(path.join(cwd, schema.fileName));
2757
+ const exist = existsSync(path__default.join(cwd, schema.fileName));
2754
2758
  if (!exist) {
2755
- await fs$1.mkdir(path.dirname(path.join(cwd, schema.fileName)), {
2759
+ await fs$1.mkdir(path__default.dirname(path__default.join(cwd, schema.fileName)), {
2756
2760
  recursive: true
2757
2761
  });
2758
2762
  }
2759
2763
  if (schema.overwrite) {
2760
- await fs$1.writeFile(path.join(cwd, schema.fileName), schema.code);
2764
+ await fs$1.writeFile(path__default.join(cwd, schema.fileName), schema.code);
2761
2765
  } else {
2762
- await fs$1.appendFile(path.join(cwd, schema.fileName), schema.code);
2766
+ await fs$1.appendFile(path__default.join(cwd, schema.fileName), schema.code);
2763
2767
  }
2764
2768
  logger.success(
2765
2769
  `\u{1F680} Schema was ${schema.overwrite ? "overwritten" : "appended"} successfully!`
@@ -2820,15 +2824,15 @@ async function generateAction(opts) {
2820
2824
  process.exit(1);
2821
2825
  }
2822
2826
  if (!options.output) {
2823
- const dirExist = existsSync(path.dirname(path.join(cwd, schema.fileName)));
2827
+ const dirExist = existsSync(path__default.dirname(path__default.join(cwd, schema.fileName)));
2824
2828
  if (!dirExist) {
2825
- await fs$1.mkdir(path.dirname(path.join(cwd, schema.fileName)), {
2829
+ await fs$1.mkdir(path__default.dirname(path__default.join(cwd, schema.fileName)), {
2826
2830
  recursive: true
2827
2831
  });
2828
2832
  }
2829
2833
  }
2830
2834
  await fs$1.writeFile(
2831
- options.output || path.join(cwd, schema.fileName),
2835
+ options.output || path__default.join(cwd, schema.fileName),
2832
2836
  schema.code
2833
2837
  );
2834
2838
  logger.success(`\u{1F680} Schema was generated successfully!`);
@@ -2853,8 +2857,8 @@ const generate = new Command("generate").option(
2853
2857
 
2854
2858
  const DEMO_URL = "https://demo.better-auth.com";
2855
2859
  const CLIENT_ID = "better-auth-cli";
2856
- const CONFIG_DIR = path.join(os.homedir(), ".better-auth");
2857
- const TOKEN_FILE = path.join(CONFIG_DIR, "token.json");
2860
+ const CONFIG_DIR = path__default.join(os__default.homedir(), ".better-auth");
2861
+ const TOKEN_FILE = path__default.join(CONFIG_DIR, "token.json");
2858
2862
  async function loginAction(opts) {
2859
2863
  const options = z.object({
2860
2864
  serverUrl: z.string().optional(),
@@ -3059,13 +3063,13 @@ const login = new Command("login").description(
3059
3063
  ).option("--server-url <url>", "The Better Auth server URL", DEMO_URL).option("--client-id <id>", "The OAuth client ID", CLIENT_ID).action(loginAction);
3060
3064
 
3061
3065
  function getSystemInfo() {
3062
- const platform = os.platform();
3063
- const arch = os.arch();
3064
- const version = os.version();
3065
- const release = os.release();
3066
- const cpus = os.cpus();
3067
- const memory = os.totalmem();
3068
- const freeMemory = os.freemem();
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();
3069
3073
  return {
3070
3074
  platform,
3071
3075
  arch,
@@ -3105,7 +3109,7 @@ function getVersion(command) {
3105
3109
  }
3106
3110
  }
3107
3111
  function getFrameworkInfo(projectRoot) {
3108
- const packageJsonPath = path.join(projectRoot, "package.json");
3112
+ const packageJsonPath = path__default.join(projectRoot, "package.json");
3109
3113
  if (!existsSync(packageJsonPath)) {
3110
3114
  return null;
3111
3115
  }
@@ -3137,7 +3141,7 @@ function getFrameworkInfo(projectRoot) {
3137
3141
  }
3138
3142
  }
3139
3143
  function getDatabaseInfo(projectRoot) {
3140
- const packageJsonPath = path.join(projectRoot, "package.json");
3144
+ const packageJsonPath = path__default.join(projectRoot, "package.json");
3141
3145
  if (!existsSync(packageJsonPath)) {
3142
3146
  return null;
3143
3147
  }
@@ -3362,7 +3366,7 @@ ${formatOutput(value, indent + 2)}`;
3362
3366
  return `${spaces}${JSON.stringify(data)}`;
3363
3367
  }
3364
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) => {
3365
- const projectRoot = path.resolve(options.cwd || process.cwd());
3369
+ const projectRoot = path__default.resolve(options.cwd || process.cwd());
3366
3370
  const systemInfo = getSystemInfo();
3367
3371
  const nodeInfo = getNodeInfo();
3368
3372
  const packageManager = getPackageManager();
@@ -3386,7 +3390,7 @@ const info = new Command("info").description("Display system and Better Auth con
3386
3390
  console.log(jsonOutput);
3387
3391
  if (options.copy) {
3388
3392
  try {
3389
- const platform = os.platform();
3393
+ const platform = os__default.platform();
3390
3394
  if (platform === "darwin") {
3391
3395
  execSync("pbcopy", { input: jsonOutput });
3392
3396
  console.log(chalk.green("\n\u2713 Copied to clipboard"));
@@ -3459,7 +3463,7 @@ Better Auth:
3459
3463
  ${JSON.stringify(betterAuthInfo, null, 2)}
3460
3464
  `;
3461
3465
  try {
3462
- const platform = os.platform();
3466
+ const platform = os__default.platform();
3463
3467
  if (platform === "darwin") {
3464
3468
  execSync("pbcopy", { input: textOutput });
3465
3469
  console.log(chalk.green("\u2713 Copied to clipboard"));
@@ -3476,6 +3480,197 @@ ${JSON.stringify(betterAuthInfo, null, 2)}
3476
3480
  }
3477
3481
  });
3478
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
+
3479
3674
  process.on("SIGINT", () => process.exit(0));
3480
3675
  process.on("SIGTERM", () => process.exit(0));
3481
3676
  async function main() {
@@ -3485,7 +3680,7 @@ async function main() {
3485
3680
  packageInfo = await getPackageInfo();
3486
3681
  } catch (error) {
3487
3682
  }
3488
- 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());
3489
3684
  program.parse();
3490
3685
  }
3491
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.6",
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.6"
60
+ "better-auth": "1.4.0-beta.7"
60
61
  },
61
62
  "files": [
62
63
  "dist"