auth 1.2.2 → 1.5.0-beta.15

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/package.json CHANGED
@@ -1,64 +1,95 @@
1
1
  {
2
2
  "name": "auth",
3
- "version": "1.2.2",
4
- "homepage": "https://cli.authjs.dev",
3
+ "version": "1.5.0-beta.15",
4
+ "type": "module",
5
+ "description": "The CLI for Better Auth",
6
+ "module": "dist/index.mjs",
5
7
  "repository": {
6
8
  "type": "git",
7
- "url": "git+https://github.com/nextauthjs/auth-cli.git"
9
+ "url": "git+https://github.com/better-auth/better-auth.git",
10
+ "directory": "packages/cli"
8
11
  },
9
- "description": "The CLI tool by Auth.js to supercharge your authentication workflows.",
10
- "author": "Balázs Orbán <info@balazsorban.com>",
11
- "contributors": [
12
- "Balázs Orbán <info@balazsorban.com>",
13
- "Nico Domino <yo@ndo.dev>",
14
- "Lluis Agusti <hi@llu.lu>",
15
- "Thang Huu Vu <hi@thvu.dev>"
16
- ],
17
- "license": "MIT",
18
- "type": "module",
19
- "bin": {
20
- "auth": "index.js"
12
+ "homepage": "https://www.better-auth.com/docs/concepts/cli",
13
+ "main": "./dist/index.mjs",
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "executableFiles": [
17
+ "./dist/index.mjs"
18
+ ]
21
19
  },
22
- "files": [
23
- "*.d.ts*",
24
- "*.js",
25
- "!scripts",
26
- "commands",
27
- "lib",
28
- "src"
29
- ],
20
+ "license": "MIT",
30
21
  "keywords": [
31
- "authjs",
32
- "cli"
22
+ "auth",
23
+ "cli",
24
+ "typescript",
25
+ "better-auth"
33
26
  ],
34
- "dependencies": {
35
- "@inkeep/ai-api": "0.8.0",
36
- "@inquirer/prompts": "5.1.0",
37
- "clipboardy": "4.0.0",
38
- "commander": "12.1.0",
39
- "open": "10.1.0",
40
- "ora": "8.1.0",
41
- "prompts": "2.4.2",
42
- "yoctocolors": "2.1.1",
43
- "zod": "3.23.8"
44
- },
45
- "prettier": {
46
- "semi": false
27
+ "exports": {
28
+ ".": "./dist/index.mjs",
29
+ "./api": {
30
+ "types": "./dist/api.d.mts",
31
+ "default": "./dist/api.mjs"
32
+ }
47
33
  },
48
- "devDependencies": {
49
- "@types/node": "18"
34
+ "typesVersions": {
35
+ "*": {
36
+ "api": [
37
+ "./dist/api.d.mts"
38
+ ]
39
+ }
50
40
  },
51
- "engines": {
52
- "node": ">=18"
41
+ "bin": {
42
+ "better-auth": "./dist/index.mjs"
53
43
  },
54
- "bugs": {
55
- "url": "https://github.com/nextauthjs/auth-cli/issues"
44
+ "devDependencies": {
45
+ "@types/better-sqlite3": "^7.6.13",
46
+ "@types/prompts": "^2.4.9",
47
+ "@types/semver": "^7.7.1",
48
+ "better-sqlite3": "^12.6.2",
49
+ "jiti": "^2.6.0",
50
+ "memfs": "^4.56.10",
51
+ "tsdown": "^0.20.3",
52
+ "tsx": "^4.20.6",
53
+ "type-fest": "^5.4.4",
54
+ "typescript": "^5.9.3",
55
+ "@better-auth/passkey": "1.5.0-beta.15"
56
56
  },
57
- "main": "index.js",
58
- "directories": {
59
- "lib": "lib"
57
+ "dependencies": {
58
+ "@babel/core": "^7.28.4",
59
+ "@babel/preset-react": "^7.27.1",
60
+ "@babel/preset-typescript": "^7.27.1",
61
+ "@better-auth/utils": "0.3.1",
62
+ "@clack/prompts": "^0.11.0",
63
+ "@mrleebo/prisma-ast": "^0.13.1",
64
+ "@prisma/client": "^5.22.0",
65
+ "@types/pg": "^8.15.5",
66
+ "c12": "^3.3.3",
67
+ "chalk": "^5.6.2",
68
+ "commander": "^12.1.0",
69
+ "dotenv": "^17.2.4",
70
+ "drizzle-orm": "^0.41.0",
71
+ "open": "^10.2.0",
72
+ "pg": "^8.16.3",
73
+ "prettier": "^3.8.1",
74
+ "prompts": "^2.4.2",
75
+ "semver": "^7.7.2",
76
+ "yocto-spinner": "^0.2.3",
77
+ "zod": "^4.3.6",
78
+ "@better-auth/core": "1.5.0-beta.15",
79
+ "@better-auth/telemetry": "1.5.0-beta.15",
80
+ "better-auth": "1.5.0-beta.15"
60
81
  },
82
+ "files": [
83
+ "dist"
84
+ ],
61
85
  "scripts": {
62
- "generate-docs": "node ./scripts/generate-docs"
86
+ "build": "tsdown",
87
+ "start": "node ./dist/index.mjs",
88
+ "lint:package": "publint run --strict",
89
+ "lint:types": "attw --profile esm-only --pack .",
90
+ "dev": "tsx ./src/index.ts",
91
+ "test": "vitest",
92
+ "coverage": "vitest run --coverage --coverage.provider=istanbul",
93
+ "typecheck": "tsc --project tsconfig.json"
63
94
  }
64
95
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Auth.js
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/commands/add.js DELETED
@@ -1,149 +0,0 @@
1
- // @ts-check
2
-
3
- import * as y from "yoctocolors"
4
- import open from "open"
5
- import clipboard from "clipboardy"
6
- import { select, input, password, number } from "@inquirer/prompts"
7
- import { requireFramework } from "../lib/detect.js"
8
- import { updateEnvFile } from "../lib/write-env.js"
9
- import { providers, frameworks } from "../lib/meta.js"
10
- import { link, markdownToAnsi } from "../lib/markdown.js"
11
- import { appleGenSecret } from "../lib/apple-gen-secret.js"
12
-
13
- /**
14
- * @param {string} label
15
- * @param {string} [defaultValue]
16
- */
17
- async function promptInput(label, defaultValue) {
18
- return input({
19
- message: `Paste ${y.magenta(label)}:`,
20
- validate: (value) => !!value,
21
- default: defaultValue,
22
- })
23
- }
24
-
25
- /** @param {string} label */
26
- async function promptPassword(label) {
27
- return password({
28
- message: `Paste ${y.magenta(label)}:`,
29
- mask: true,
30
- validate: (value) => !!value,
31
- })
32
- }
33
-
34
- const choices = Object.entries(providers)
35
- .filter(([, { setupUrl }]) => !!setupUrl)
36
- .map(([value, { name }]) => ({ name, value }))
37
-
38
- /** @param {string | undefined} providerId */
39
- export async function action(providerId) {
40
- try {
41
- providerId ??= await select({
42
- message: "What provider do you want to set up?",
43
- choices: choices,
44
- })
45
-
46
- const provider = providers[providerId]
47
- if (!provider?.setupUrl) {
48
- console.error(
49
- y.red(
50
- `Missing instructions for ${
51
- provider?.name ?? providerId
52
- }.\nInstructions are available for: ${y.bold(
53
- choices.map((choice) => choice.name).join(", ")
54
- )}`
55
- )
56
- )
57
- return
58
- }
59
-
60
- const frameworkId = await requireFramework()
61
- const framework = frameworks[frameworkId]
62
-
63
- console.log(
64
- y.dim(
65
- `Setting up OAuth provider in your ${framework.name} app (${link(
66
- "more info",
67
- "https://authjs.dev/getting-started/authentication/oauth"
68
- )})...\n`
69
- )
70
- )
71
-
72
- const url = new URL(
73
- `${framework.path}/callback/${providerId}`,
74
- `http://localhost:${framework.port}`
75
- )
76
-
77
- clipboard.writeSync(url.toString())
78
- console.log(
79
- `\
80
- ${y.bold("Setup URL")}: ${provider.setupUrl}
81
- ${y.bold("Callback URL (copied to clipboard)")}: ${url}`
82
- )
83
-
84
- console.log("_________________________")
85
- if (provider.instructions) {
86
- console.log(y.dim("\nFollow the instructions:\n"))
87
- console.log(markdownToAnsi(provider.instructions))
88
- }
89
- console.log(
90
- y.dim(
91
- `\nProvider documentation: https://providers.authjs.dev/${providerId}\n`
92
- )
93
- )
94
- console.log("‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾")
95
- console.log(y.dim("Opening setup URL in your browser...\n"))
96
- await new Promise((resolve) => setTimeout(resolve, 3000))
97
-
98
- await open(provider.setupUrl)
99
-
100
- if (providerId === "apple") {
101
- const clientId = await promptInput("Client ID")
102
- const keyId = await promptInput("Key ID")
103
- const teamId = await promptInput("Team ID")
104
- const privateKey = await input({
105
- message: "Path to Private Key",
106
- validate: (value) => !!value,
107
- default: "./private-key.p8",
108
- })
109
-
110
- const expiresInDays =
111
- (await number({
112
- message: "Expires in days (default: 180)",
113
- required: false,
114
- default: 180,
115
- })) ?? 180
116
-
117
- console.log(y.dim("Updating environment variable file..."))
118
-
119
- await updateEnvFile({ AUTH_APPLE_ID: clientId })
120
-
121
- const secret = await appleGenSecret({
122
- teamId,
123
- clientId,
124
- keyId,
125
- privateKey,
126
- expiresInDays,
127
- })
128
-
129
- await updateEnvFile({ AUTH_APPLE_SECRET: secret })
130
- } else {
131
- const clientId = await promptInput("Client ID")
132
- const clientSecret = await promptPassword("Client Secret")
133
-
134
- console.log(y.dim("Updating environment variable file..."))
135
-
136
- const varPrefix = `AUTH_${providerId.toUpperCase()}`
137
- await updateEnvFile({
138
- [`${varPrefix}_ID`]: clientId,
139
- [`${varPrefix}_SECRET`]: clientSecret,
140
- })
141
- }
142
-
143
- console.log("\n🎉 Done! You can now use this provider in your app.")
144
- } catch (error) {
145
- if (!(error instanceof Error)) return
146
- if (error.message.startsWith("User force closed")) return
147
- throw error
148
- }
149
- }
package/commands/ask.js DELETED
@@ -1,90 +0,0 @@
1
- // @ts-check
2
-
3
- import * as y from "yoctocolors"
4
- import { input } from "@inquirer/prompts"
5
- import { InkeepAI } from "@inkeep/ai-api"
6
- import { ChatModeOptions } from "@inkeep/ai-api/models/components/index.js"
7
- import * as ora from "ora"
8
- import { link, markdownToAnsi, breakStringToLines } from "../lib/markdown.js"
9
-
10
- const INKEEP_API_KEY = "e32967a320a48a2cd933922099e1f38f6ebb4ab62ff98343"
11
- const INKEEP_INTEGRATION_ID = "clvn0fdez000cip0e5w2oaobw"
12
-
13
- const inkeepAI = new InkeepAI({ apiKey: INKEEP_API_KEY })
14
-
15
- function randomSpinner() {
16
- const allSpinners = Object.keys(ora.spinners)
17
- const max = allSpinners.length - 1
18
- const random = Math.floor(Math.random() * (max + 1))
19
- return allSpinners[random]
20
- }
21
-
22
- export async function action({ stream = false, raw = false }) {
23
- const format = raw ? (i) => i : markdownToAnsi
24
- const newLocal = randomSpinner()
25
- const spinner = ora.default({
26
- text: "Understanding question",
27
- // @ts-expect-error
28
- spinner: newLocal,
29
- })
30
- try {
31
- const content = await input({ message: "What would you like to know: " })
32
-
33
- spinner.start()
34
-
35
- const result = await inkeepAI.chatSession.create({
36
- integrationId: INKEEP_INTEGRATION_ID,
37
- stream,
38
- chatSession: { messages: [{ content, role: "user" }] },
39
- chatMode: ChatModeOptions.Auto,
40
- })
41
-
42
- if (stream) {
43
- if (result.chatResultStream == null) {
44
- throw new Error("failed to create stream: received null value")
45
- }
46
-
47
- spinner.stop().clear()
48
-
49
- for await (const event of result.chatResultStream) {
50
- if (event.event === "message_chunk") {
51
- const content = format(event.data.contentChunk)
52
- process.stdout.write(content)
53
- }
54
- }
55
- } else {
56
- const answer = result.chatResult?.message.content
57
- if (!answer) return console.error(y.red("Could not get an answer."))
58
-
59
- console.log(breakStringToLines(format(answer), 80))
60
- }
61
-
62
- console.log(
63
- y.italic(
64
- `\n\nAnswered by ${y.cyan(
65
- link("Inkeep AI", "https://inkeep.com")
66
- )}. Check out the official ${y.magenta(
67
- link("Auth.js", "https://authjs.dev")
68
- )} docs.`
69
- )
70
- )
71
- } catch (e) {
72
- spinner.stop().clear()
73
- if (!(e instanceof Error)) return
74
- if (e.message.startsWith("User force closed")) return
75
-
76
- console.error(y.red(e.stack ?? e.message))
77
- console.error(
78
- y.bold(
79
- y.red(
80
- `\n This is a bug. Please report it on ${link(
81
- "GitHub",
82
- "https://github.com/nextauthjs/auth-cli/issues"
83
- )}.`
84
- )
85
- )
86
- )
87
- } finally {
88
- spinner.stop().clear()
89
- }
90
- }
package/commands/index.js DELETED
@@ -1,4 +0,0 @@
1
- export * as ask from "./ask.js"
2
- export * as init from "./init.js"
3
- export * as secret from "./secret.js"
4
- export * as add from './add.js'
package/commands/init.js DELETED
@@ -1,121 +0,0 @@
1
- // @ts-check
2
- import { execSync } from "node:child_process"
3
- import { input, confirm, select, checkbox } from "@inquirer/prompts"
4
- import * as y from "yoctocolors"
5
- import { action as secretAction } from "./secret.js"
6
-
7
- import { getPkgManager, install } from "../lib/pkg-manager.js"
8
- import * as meta from "../lib/meta.js"
9
- import { updateEnvFile } from "../lib/write-env.js"
10
- import { mkdir } from "node:fs/promises"
11
-
12
- /**
13
- * @param {string} framework
14
- * @param {{example?: boolean}} options
15
- * @returns
16
- */
17
- export async function action(framework, options) {
18
- try {
19
- if (!framework) {
20
- framework = await select({
21
- message: "Select a framework",
22
- choices: Object.entries(meta.frameworks).map(([key, value]) => ({
23
- name: `${value.name} ${y.dim(`(${key})`)}`,
24
- value: key,
25
- })),
26
- })
27
- }
28
-
29
- const dir = await input({
30
- message: "Name of the project",
31
- default: `my-${framework}-app`,
32
- })
33
-
34
- if (options.example) await createFromExample(framework, dir)
35
-
36
- const providers = await checkbox({
37
- instructions: false,
38
- message: "Select one or multiple providers",
39
- choices: Object.entries(meta.providers).map(([value, { name }]) => ({
40
- name,
41
- value,
42
- })),
43
- })
44
-
45
- /** @type {string|undefined} */
46
- let adapter = await select({
47
- default: "none",
48
- message: "Select a database adapter",
49
- choices: Object.entries(meta.adapters).map(([value, name]) => ({
50
- name,
51
- value,
52
- })),
53
- })
54
- adapter = adapter === "none" ? undefined : adapter
55
-
56
- await scaffoldProject({ framework, dir, providers, adapter })
57
- } catch (e) {
58
- if (!(e instanceof Error)) return
59
- if (e.message.startsWith("User force closed")) return
60
-
61
- console.error(y.red(e.message))
62
- }
63
- }
64
-
65
- /**
66
- * @param {string} framework
67
- * @param {string} dir
68
- */
69
- async function createFromExample(framework, dir) {
70
- const { src, demo } = meta.frameworks[framework]
71
- execSync(`git clone ${src} ${dir}`)
72
- if (
73
- await confirm({
74
- message: "Initiailze .env with `AUTH_SECRET`",
75
- default: true,
76
- })
77
- ) {
78
- execSync(`cd ${dir}`)
79
- await secretAction({ path: dir })
80
- }
81
-
82
- await install()
83
-
84
- console.log(`
85
- Project ${y.italic(`\`${dir}\``)} has been created.
86
- Source code: ${src}
87
- Deployed demo: ${demo}`)
88
- }
89
-
90
- /**
91
- * @param {{framework: string, dir: string, providers: string[], adapter?: string}} options
92
- */
93
- async function scaffoldProject(options) {
94
- const { framework, providers, dir, adapter } = options
95
- const pkgManager = getPkgManager()
96
- console.log(
97
- `Scaffolding ${y.bold(framework)} project with ${y.bold(
98
- pkgManager
99
- )} at ${y.bold(dir)}...`
100
- )
101
- throw new Error("Scaffolding not implemented. Please use `init --example`")
102
- console.log(`Create directory ${dir}`)
103
- await mkdir(dir)
104
- console.log(`Change directory to ${dir}`)
105
- execSync(`cd ${dir}`)
106
- console.log(`Initialize ${pkgManager} project`)
107
- execSync(`${pkgManager} init`)
108
- // console.log(`Add ${framework} to ${pkgManager}`)
109
- // execSync(`${pkgManager} install ${framework}`)
110
- for (const provider of providers) {
111
- const id = `AUTH_${provider.toUpperCase()}_ID`
112
- const secret = `AUTH_${provider.toUpperCase()}_SECRET`
113
- await updateEnvFile(
114
- {
115
- [id]: "",
116
- [secret]: "",
117
- },
118
- dir
119
- )
120
- }
121
- }
@@ -1,55 +0,0 @@
1
- // @ts-check
2
-
3
- import * as y from "yoctocolors"
4
- import clipboard from "clipboardy"
5
- import { requireFramework } from "../lib/detect.js"
6
- import { updateEnvFile } from "../lib/write-env.js"
7
-
8
- /** Web compatible method to create a random string of a given length */
9
- function randomString(size = 32) {
10
- const bytes = crypto.getRandomValues(new Uint8Array(size))
11
- // @ts-expect-error
12
- return Buffer.from(bytes, "base64").toString("base64")
13
- }
14
-
15
- /**
16
- * @param {{
17
- * copy?: boolean
18
- * path?: string
19
- * raw?: boolean
20
- * }} options
21
- */
22
- export async function action(options) {
23
- const key = "AUTH_SECRET"
24
- const value = randomString()
25
- if (options.raw) return console.log(value)
26
-
27
- const line = `${key}="${value}"`
28
- const message = {
29
- introClipboard:
30
- "Secret generated. It has been copied to your clipboard, paste it to your .env/.env.local file to continue.",
31
- introCopy:
32
- "Secret generated. Copy it to your .env/.env.local file (depending on your framework):",
33
- value: `\n${line}`,
34
- }
35
-
36
- if (options.copy) {
37
- try {
38
- clipboard.writeSync(line)
39
- console.log(message.introClipboard)
40
- } catch (error) {
41
- console.error(y.red(error))
42
- console.log(message.introCopy)
43
- } finally {
44
- console.log(message.value)
45
- process.exit(0)
46
- }
47
- }
48
-
49
- try {
50
- await requireFramework(options.path)
51
- await updateEnvFile({ [key]: value }, options.path)
52
- } catch (error) {
53
- console.error(y.red(error))
54
- }
55
- }
package/index.js DELETED
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // @ts-check
4
-
5
- import { Command, InvalidArgumentError } from "commander"
6
- import * as y from "yoctocolors"
7
- import { ask, init, secret, add } from "./commands/index.js"
8
-
9
- // import pkg from "./package.json" assert { type: "json" }
10
-
11
- import fs from "node:fs/promises"
12
- import { join } from "node:path"
13
- import { fileURLToPath } from "node:url"
14
-
15
- const __dirname = fileURLToPath(new URL(".", import.meta.url))
16
- const pkg = JSON.parse(
17
- await fs.readFile(join(__dirname, "./package.json"), "utf-8")
18
- )
19
- const { name, description, version } = pkg
20
-
21
- try {
22
- // TODO: Remove when Node.js 18 is not maintained anymore
23
- // @ts-expect-error
24
- globalThis.crypto ??= (await import("crypto")).webcrypto
25
- } catch {}
26
-
27
- const program = new Command()
28
-
29
- program
30
- .name(name)
31
- .description(description.replace("Auth.js", y.magenta(y.bold("Auth.js"))))
32
- .version(version)
33
-
34
- program
35
- .command("ask")
36
- .option("--stream", "Stream the response.")
37
- .option("--raw", "Show the Markdown response without formatting.")
38
- .description("Ask about docs, API, or auth concepts.")
39
- .action(ask.action)
40
-
41
- program
42
- .command("init")
43
- .argument("[framework]", "The framework to use.")
44
- .option("-e, --example", "Clone a full example.")
45
- .description("Initialize a project.")
46
- .action(init.action)
47
-
48
- program
49
- .command("secret")
50
- .option("--raw", "Output the string without any formatting.")
51
- .option("--copy", 'Copy AUTH_SECRET="value".')
52
- .description("Generate a random string and add it to the .env file.")
53
- .action(secret.action)
54
-
55
- program
56
- .command("add")
57
- .argument("[provider]", "The authentication provider.")
58
- .description('Register a new authentication provider')
59
- .action(add.action)
60
-
61
- program.parse()
62
-
63
- export { program }