create-tnt-stack 0.4.4-beta.79d5e73 → 0.5.0
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 +1 -1
- package/dist/index.js +19 -19
- package/package.json +86 -86
- package/template/base/README.md +1 -1
- package/template/packages/prisma/schema/{with-next-auth.prisma → with-authjs.prisma} +2 -2
- package/template/packages/src/app/page/with-authjs.tsx +126 -0
- package/template/packages/src/server/auth/authjs.ts +5 -0
- package/template/packages/src/server/auth/config/authjs-with-prisma.ts +30 -0
- package/template/packages/src/server/auth/config/authjs.ts +27 -0
- package/template/packages/src/server/auth/config/next-auth-with-prisma.ts +0 -60
- package/template/packages/src/server/auth/config/next-auth.ts +0 -57
- package/template/packages/src/server/auth/next-auth.ts +0 -10
- /package/template/packages/src/env/{with-next-auth-db.js → with-authjs-db.js} +0 -0
- /package/template/packages/src/env/{with-next-auth.js → with-authjs.js} +0 -0
package/README.md
CHANGED
@@ -41,7 +41,7 @@ Simply run `npm create tnt-stack@latest` to get started!
|
|
41
41
|
TNT-Powered installs **TypeScript, Next.js, Tailwind CSS**, along with:
|
42
42
|
|
43
43
|
- ✅ **Payload CMS** - A powerful headless CMS
|
44
|
-
- ✅ **
|
44
|
+
- ✅ **Auth.js** - Authentication made easy
|
45
45
|
- ✅ **Lucia Auth** - Authentication following
|
46
46
|
[Luca Auth Guidelines](https://lucia-auth.com/)
|
47
47
|
- ✅ **Prisma ORM** - Database management with full type safety
|
package/dist/index.js
CHANGED
@@ -1,32 +1,32 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
import Fe from"path";import{execa as wt}from"execa";import Le from"fs-extra";import{confirm as J,input as he,select as
|
2
|
+
import Fe from"path";import{execa as wt}from"execa";import Le from"fs-extra";import{confirm as J,input as he,select as x}from"@inquirer/prompts";import{Command as nt}from"commander";import X from"path";import{fileURLToPath as Ve}from"url";var ze=Ve(import.meta.url),Ke=X.dirname(ze),p=X.join(Ke,"../"),Z=` ___ ___ ___ _ _____ ___ _____ _ _ _____ ___ _____ _ ___ _ __
|
3
3
|
/ __| _ \\ __| /_\\_ _| __| |_ _| \\| |_ _| / __|_ _/_\\ / __| |/ /
|
4
4
|
| (__| / _| / _ \\| | | _| | | | .\` | | | \\__ \\ | |/ _ \\ (__| ' <
|
5
5
|
\\___|_|_\\___/_/ \\_\\_| |___| |_| |_|\\_| |_| |___/ |_/_/ \\_\\___|_|\\_\\
|
6
|
-
`,
|
6
|
+
`,j="my-tnt-app",G="create-tnt-stack";import y from"path";import k from"fs-extra";import te from"path";import ae from"fs-extra";import He from"sort-package-json";var ee={"next-auth":"^5.0.0-beta.25","@auth/prisma-adapter":"^2.8.0",prisma:"^6.5.0","@prisma/client":"^6.5.0","@t3-oss/env-nextjs":"^0.12.0",zod:"^3.24.2",prettier:"^3.5.3","prettier-plugin-tailwindcss":"^0.6.11","@ianvs/prettier-plugin-sort-imports":"^4.4.1",eslint:"^9","eslint-config-next":"^15.2.4","@eslint/eslintrc":"^3.3.1",typescript:"^5.8.2","@types/node":"^22","@types/react":"^19","@types/react-dom":"^19",payload:"^3.33.0","@payloadcms/next":"^3.33.0","@payloadcms/payload-cloud":"^3.33.0","@payloadcms/richtext-lexical":"^3.33.0","@payloadcms/db-vercel-postgres":"^3.33.0","@payloadcms/db-sqlite":"^3.33.0",graphql:"^16.10.0",sharp:"^0.34.1"};var f=e=>{let{dependencies:n,devMode:o,projectDir:s}=e,t=ae.readJsonSync(te.join(s,"package.json"));n.forEach(i=>{let l=ee[i];o&&t.devDependencies?t.devDependencies[i]=l:t.dependencies&&(t.dependencies[i]=l)});let a=He(t);ae.writeJsonSync(te.join(s,"package.json"),a,{spaces:2})};var ne=({projectDir:e,packages:n,databaseProvider:o})=>{let s=[],t=[];if(n?.payload.inUse)switch(s.push("payload"),s.push("@payloadcms/next"),s.push("@payloadcms/payload-cloud"),s.push("@payloadcms/richtext-lexical"),s.push("graphql"),o){case"sqlite":t.push("@payloadcms/db-sqlite");break;case"postgresql":t.push("@payloadcms/db-vercel-postgres");break}f({projectDir:e,dependencies:s,devMode:!1}),f({projectDir:e,dependencies:t,devMode:!1});let a=y.join(p,"template/packages"),i=y.join(a,"config/payload",`${o==="postgresql"?"with-postgres":"with-sqlite"}.ts`),l=y.join(e,"payload.config.ts");k.copyFileSync(i,l);let d=y.join(a,"src/payload/collections"),g=y.join(e,"src/collections");k.mkdirSync(g,{recursive:!0}),k.copyFileSync(y.join(d,"Media.ts"),y.join(g,"Media.ts")),k.copyFileSync(y.join(d,"Users.ts"),y.join(g,"Users.ts"));let u=y.join(a,"src/app/(payload)"),m=y.join(e,"src/app/(payload)");k.mkdirSync(m,{recursive:!0}),k.copySync(u,m);let b=y.join(e,"package.json"),_=k.readJSONSync(b);_.scripts={..._.scripts,payload:"payload","generate:importmap":"payload generate:importmap","generate:types":"payload generate:types"},k.writeJSONSync(b,_,{spaces:2})};import oe from"path";import Ye from"fs-extra";var se=({projectDir:e,packages:n})=>{let o=n?.typescript.inUse,s=n?.payload.inUse,t=[];o&&(t.push("typescript"),t.push("@types/node"),t.push("@types/react"),t.push("@types/react-dom")),f({projectDir:e,dependencies:t,devMode:!0});let a=oe.join(p,"template/packages/config/tsconfig",`${s?"with-payload":"base"}.json`),i=oe.join(e,"tsconfig.json");Ye.copyFileSync(a,i)};import S from"path";import U from"fs-extra";var ie=({projectDir:e,packages:n})=>{let o=n?.prisma.inUse,s=["next-auth"];o&&s.push("@auth/prisma-adapter"),f({projectDir:e,dependencies:s,devMode:!1});let t=S.join(p,"template/packages"),a="src/app/api/auth/[...nextauth]/route.ts",i=S.join(t,a),l=S.join(e,a),d=S.join(t,"src/server/auth/config",o?"authjs-with-prisma.ts":"authjs.ts"),g=S.join(e,"src/server/auth/config.ts"),u=S.join(t,"src/server/auth/authjs.ts"),m=S.join(e,"src/server/auth/index.ts");U.copySync(i,l),U.copySync(d,g),U.copySync(u,m)};import M from"path";import F from"fs-extra";var re=({projectDir:e,scopedAppName:n,packages:o,databaseProvider:s})=>{let t=o?.envVariables.inUse,a=o?.authjs.inUse,i=o?.prisma.inUse,l=o?.payload.inUse,d=[];t&&(d.push("@t3-oss/env-nextjs"),d.push("zod")),f({projectDir:e,dependencies:d,devMode:!1});let g=i||l,u=Qe(!!a,!!i,!!l,n,s),m="";if(g?a?m="with-authjs-db.js":l?m="with-payload.js":m="with-db.js":a&&(m="with-authjs.js"),m!==""){let We=M.join(p,"template/packages/src/env",m),Be=M.join(e,"src/env.js");F.copyFileSync(We,Be)}let b=M.join(e,".env"),_=M.join(e,".env.example"),qe=Xe+u,Q=Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString("base64"),Je=u.replace('AUTH_SECRET=""',`AUTH_SECRET="${Q}" # Generated by create-tnt-stack`).replace('PAYLOAD_SECRET=""',`PAYLOAD_SECRET="${Q}" # Generated by create-tnt-stack`);F.writeFileSync(b,Je,"utf-8"),F.writeFileSync(_,qe,"utf-8")};function Qe(e,n,o,s,t){let a=`
|
7
7
|
# When adding additional environment variables, the schema in "/src/env.js"
|
8
8
|
# should be updated accordingly.
|
9
9
|
`.trim().concat(`
|
10
10
|
`);return n&&(a+=`
|
11
11
|
# Prisma
|
12
12
|
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
|
13
|
-
`),n&&(t==="mysql"?a+=`DATABASE_URL="mysql://root:password@localhost:3306/${
|
14
|
-
`),
|
13
|
+
`),n&&(t==="mysql"?a+=`DATABASE_URL="mysql://root:password@localhost:3306/${s}"`:t==="postgresql"?a+=`DATABASE_URL="postgresql://postgres:password@localhost:5432/${s}"`:t==="sqlite"&&(a+='DATABASE_URL="file:./db.sqlite"'),a+=`
|
14
|
+
`),o&&(a+=`
|
15
15
|
# Payload CMS
|
16
16
|
# https://payloadcms.com/docs/database/overview
|
17
17
|
`,a+=`PAYLOAD_SECRET=""
|
18
|
-
`,t==="postgresql"?a+=`DATABASE_URL="postgresql://postgres:password@localhost:5432/${
|
18
|
+
`,t==="postgresql"?a+=`DATABASE_URL="postgresql://postgres:password@localhost:5432/${s}"`:t==="sqlite"&&(a+='DATABASE_URL="file:./db.sqlite"'),a+=`
|
19
19
|
`),e&&(a+=`
|
20
20
|
# Next Auth
|
21
21
|
# You can generate a new secret on the command line with:
|
22
22
|
# npx auth secret
|
23
|
-
# https://
|
23
|
+
# https://authjs.dev/getting-started/installation#setup-environment
|
24
24
|
AUTH_SECRET=""
|
25
25
|
|
26
26
|
# Next Auth Discord Provider
|
27
27
|
DISCORD_CLIENT_ID=""
|
28
28
|
DISCORD_CLIENT_SECRET=""
|
29
|
-
`),!e&&!n&&!
|
29
|
+
`),!e&&!n&&!o&&(a+=`
|
30
30
|
# Example:
|
31
31
|
# SERVERVAR="foo"
|
32
32
|
# NEXT_PUBLIC_CLIENTVAR="bar"
|
@@ -40,19 +40,19 @@ DISCORD_CLIENT_SECRET=""
|
|
40
40
|
# ".env" and populate it with your secrets.
|
41
41
|
`.trim().concat(`
|
42
42
|
|
43
|
-
`);import
|
43
|
+
`);import L from"path";import q from"fs-extra";var le=({projectDir:e,packages:n})=>{let o=n?.eslint.inUse,s=[];o&&(s.push("eslint"),s.push("eslint-config-next"),s.push("@eslint/eslintrc")),f({projectDir:e,dependencies:s,devMode:!0});let t=L.join(p,"template/packages/config","eslint.config.mjs"),a=L.join(e,"eslint.config.mjs"),i=L.join(e,"package.json"),l=q.readJSONSync(i);l.scripts={...l.scripts,lint:"next lint"},q.copyFileSync(t,a),q.writeJSONSync(i,l,{spaces:2})};import pe from"path";import Ze from"fs-extra";var ce=({projectDir:e,packages:n})=>{let o=n?.prettier.inUse,s=[];o&&(s.push("prettier"),s.push("prettier-plugin-tailwindcss"),s.push("@ianvs/prettier-plugin-sort-imports")),f({projectDir:e,dependencies:s,devMode:!0});let t=pe.join(p,"template/packages/config","prettier.config.mjs"),a=pe.join(e,"prettier.config.mjs");Ze.copyFileSync(t,a)};import w from"path";import P from"fs-extra";var me=({projectDir:e,packages:n,databaseProvider:o})=>{f({projectDir:e,dependencies:["prisma"],devMode:!0}),f({projectDir:e,dependencies:["@prisma/client"],devMode:!1});let s=w.join(p,"template/packages"),t=w.join(s,"prisma/schema",`${n?.authjs.inUse?"with-authjs":"base"}.prisma`),a=P.readFileSync(t,"utf-8");o!=="sqlite"&&(a=a.replace('provider = "sqlite"',`provider = "${{mysql:"mysql",postgresql:"postgresql"}[o]}"`),["mysql"].includes(o)&&(a=a.replace("// @db.Text","@db.Text")));let i=w.join(e,"prisma/schema.prisma");P.mkdirSync(w.dirname(i),{recursive:!0}),P.writeFileSync(i,a);let l=w.join(s,"src/server/db/db-prisma.ts"),d=w.join(e,"src/server/db/index.ts");P.mkdirSync(w.dirname(d),{recursive:!0}),P.writeFileSync(d,P.readFileSync(l,"utf-8"));let g=w.join(e,"package.json"),u=P.readJSONSync(g);u.scripts={...u.scripts,postinstall:"prisma generate","db:push":"prisma db push","db:studio":"prisma studio","db:generate":"prisma migrate dev","db:migrate":"prisma migrate deploy"},P.writeJSONSync(g,u,{spaces:2})};var de=["none","authjs"],fe=["none","prisma"],R=["sqlite","mysql","postgresql"];var ge=e=>({authjs:{inUse:e.includes("authjs"),installer:ie},prisma:{inUse:e.includes("prisma"),installer:me},envVariables:{inUse:!0,installer:re},prettier:{inUse:e.includes("prettier"),installer:ce},eslint:{inUse:e.includes("eslint"),installer:le},typescript:{inUse:!0,installer:se},payload:{inUse:e.includes("payload"),installer:ne}});import et from"path";import tt from"fs-extra";function A(){let e=et.join(p,"package.json");return tt.readJSONSync(e).version??"1.0.0"}var h=()=>{let e=process.env.npm_config_user_agent;return e?e.startsWith("yarn")?"yarn":e.startsWith("pnpm")?"pnpm":e.startsWith("bun")?"bun":"npm":"npm"};var C=class extends Error{constructor(n){super(n)}};import E from"chalk";var r={error(...e){console.log(E.red(...e))},warn(...e){console.log(E.yellow(...e))},info(...e){console.log(E.cyan(...e))},success(...e){console.log(E.green(...e))}};var N=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e);var at=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;function ue(e){let n=N(e),o=n.split("/"),s=o.findIndex(a=>a.startsWith("@")),t=o[o.length-1];return o.findIndex(a=>a.startsWith("@"))!==-1&&(t=o.slice(s).join("/")),n=="."||at.test(t??"")?!0:"App name must consist of only lowercase alphanumeric characters, '-', and '_'"}var ye=e=>e.startsWith(".")||e.startsWith("/")?"Import alias can't start with '.' or '/'":!0;var c={appName:j,packages:[],flags:{noGit:!1,noInstall:!1,default:!1,CI:!1,authentication:"none",orm:"none",formatter:"prettier",linter:"eslint",importAlias:"@/",dbProvider:"sqlite",backend:"nextjs"},databaseProvider:"sqlite"};async function be(){let e=c,n=new nt().name(G).description("CLI for scaffolding new web apps with the TNT-Powered stack").version(A(),"-v, --version","Output the current version of Create TNT Stack").argument("[dir]","The name of the application, as well as the name of the directory to create").option("--noGit","Explicitly tell the CLI to not initialize a new git repo in the project",!1).option("--noInstall","Explicitly tell the CLI to not run the package manager's install command",!1).option("-y, --default","Bypass the CLI and use all default options to bootstrap a new tnt-stack",!1).option("--CI","Boolean value if we're running in CI",!1).option("--backend [framework]",`Choose a backend framework to use. Possible values: ${c.flags.backend}`,c.flags.backend).option("--authProvider [provider]",`Choose an authentication provider to use. Possible values: ${de.join(", ")}`,c.flags.authentication).option("--databaseORM [orm]",`Choose a database ORM to use. Possible values: ${fe.join(", ")}`,c.flags.orm).option("--formatter [formatter]",`Choose a formatter to use. Possible values: ${c.flags.formatter}`,c.flags.formatter).option("--linter [linter]",`Choose a linter to use. Possible values: ${c.flags.linter}`,c.flags.linter).option("-i, --import-alias [alias]","Explicitly tell the CLI to use a custom import alias",c.flags.importAlias).option("--dbProvider [provider]",`Choose a database provider to use. Possible values: ${R.join(", ")}`,c.flags.dbProvider).parse(process.argv);process.env.npm_config_user_agent?.startsWith("yarn/3")&&r.warn(` WARNING: It looks like you are using Yarn 3. This is currently not supported,
|
44
44
|
and likely to result in a crash. Please run create-tnt-stack with another
|
45
45
|
package manager such as pnpm, npm, or Yarn Classic.
|
46
|
-
See: https://github.com/t3-oss/create-t3-app/issues/57`);let
|
46
|
+
See: https://github.com/t3-oss/create-t3-app/issues/57`);let o=n.args[0];if(o&&(e.appName=o),e.flags=n.opts(),e.flags.CI){switch(e.packages=[],e.flags.backend){case"payload":e.packages.push("payload");break;default:break}switch(e.flags.authentication){case"authjs":e.packages.push("authjs");break;default:break}switch(e.flags.orm){case"prisma":e.packages.push("prisma");break;default:break}switch(e.flags.formatter){case"prettier":e.packages.push("prettier");break;default:break}switch(e.flags.linter){case"eslint":e.packages.push("eslint");break;default:break}return R.includes(e.flags.dbProvider)===!1&&(r.warn(`Incompatible database provided. Use: ${R.join(", ")}. Exiting.`),process.exit(0)),e.flags.backend==="payload"&&e.flags.dbProvider==="mysql"&&(r.warn("Payload CMS does not support MySQL. Exiting."),process.exit(0)),e}if(e.flags.default)return e;try{if(process.env.TERM_PROGRAM?.toLowerCase().includes("mintty"))throw r.warn(` WARNING: It looks like you are using MinTTY, which is non-interactive. This is most likely because you are
|
47
47
|
using Git Bash. If that's that case, please use Git Bash from another terminal, such as Windows Terminal. Alternatively, you
|
48
|
-
can provide the arguments from the CLI directly: https://create.tntstack.org/
|
49
|
-
Using: ${
|
48
|
+
can provide the arguments from the CLI directly: https://create.tntstack.org/getting-started#experimental-ci-flags to skip the prompts.`),new C("Non-interactive environment");let s=h(),t={};o||(t.name=await he({message:"What will your project be called?",default:j,validate:i=>ue(i)})),t.backend=await x({message:"What backend framework would you like to use?",choices:[{value:"nextjs",name:"Next.js"},{value:"payload",name:"Payload CMS"}],default:!c.flags.backend}),t.backend==="payload"&&(t.databaseProvider=await x({message:"What database provider would you like to use?",choices:[{value:"sqlite",name:"SQLite"},{value:"postgresql",name:"PostgreSQL"}],default:!c.flags.dbProvider})),t.backend==="nextjs"&&(t.authentication=await x({message:"What authentication provider would you like to use?",choices:[{value:"none",name:"None"},{value:"authjs",name:"Auth.js"}],default:!c.flags.authentication}),t.orm=await x({message:"What database ORM would you like to use?",choices:[{value:"none",name:"None"},{value:"prisma",name:"Prisma"}],default:!c.flags.orm}),t.orm!=="none"&&(t.databaseProvider=await x({message:"What database provider would you like to use?",choices:[{value:"sqlite",name:"SQLite"},{value:"mysql",name:"MySQL"},{value:"postgresql",name:"PostgreSQL"}],default:!c.flags.dbProvider}))),t.formatter=await x({message:"What formatter would you like to use?",choices:[{value:"none",name:"None"},{value:"prettier",name:"Prettier"}],default:!c.flags.formatter}),t.linter=await x({message:"What linter would you like to use?",choices:[{value:"eslint",name:"ESLint"}],default:!c.flags.linter}),e.flags.noGit||(t.noGit=await J({message:"Should we initialize a Git repository and stage the changes?",default:!c.flags.noGit})),e.flags.noInstall||(t.noInstall=await J({message:`Should we run '${s}`+(s==="yarn"?"'?":" install' for you?"),default:!c.flags.noInstall})),t.importAlias=await he({message:"What import alias would you like to use?",default:c.flags.importAlias,validate:ye});let a=[];switch(t.backend){case"payload":a.push("payload");break;default:break}switch(t.authentication){case"authjs":a.push("authjs");break;default:break}switch(t.orm){case"prisma":a.push("prisma");break;default:break}switch(t.formatter){case"prettier":a.push("prettier");break;default:break}switch(t.linter){case"eslint":a.push("eslint");break;default:break}return{appName:t.name??e.appName,packages:a,flags:{...e.flags,noGit:!t.noGit||e.flags.noGit,noInstall:!t.noInstall||e.flags.noInstall,importAlias:t.importAlias??e.flags.importAlias},databaseProvider:t.databaseProvider||"sqlite"}}catch(s){if(s instanceof C)r.warn(`${G} needs an interactive terminal to run.`),await J({message:"Continue scaffolding with default options?",default:!0})||(r.info("Exiting..."),process.exit(0)),r.info(`Scaffolding default tnt app in ./${e.appName}`);else throw s}return e}import lt from"path";import ve from"chalk";import ot from"ora";function ke(e){let{packages:n}=e;r.info("Adding boilerplate...");for(let[o,s]of Object.entries(n))if(s.inUse){let t=ot(`Boilerplating ${o}...`).start();s.installer(e),t.succeed(ve.green(`${ve.green.bold(o)}`))}r.info("")}import W from"path";import{confirm as st,select as it}from"@inquirer/prompts";import I from"chalk";import O from"fs-extra";import rt from"ora";async function we({projectName:e,projectDir:n,pkgManager:o,noInstall:s}){let t=W.join(p,"template/base");s?r.info(""):r.info(`
|
49
|
+
Using: ${I.cyan.bold(o)}
|
50
50
|
`);let a=rt(`Scaffolding in: ${n}...
|
51
|
-
`).start();if(
|
52
|
-
`);else{a.stopAndPersist();let l=await it({message:`${
|
53
|
-
`),
|
54
|
-
`)}import v from"path";import B from"fs-extra";function Pe({packages:e,projectDir:n}){let
|
55
|
-
`).start(),
|
56
|
-
`)}catch{n.fail(`${
|
57
|
-
`)}}import ft from"chalk";import{execa as
|
58
|
-
`))};var De=async({projectName:e=
|
51
|
+
`).start();if(O.existsSync(n))if(O.readdirSync(n).length===0)e!=="."&&a.info(`${I.cyan.bold(e)} exists but is empty, continuing...
|
52
|
+
`);else{a.stopAndPersist();let l=await it({message:`${I.redBright.bold("Warning:")} ${I.cyan.bold(e)} already exists and isn't empty. How would you like to proceed?`,choices:[{value:"abort",name:"Abort installation (recommended)"},{value:"clear",name:"Clear the directory and continue installation"},{value:"overwrite",name:"Continue installation and overwrite conflicting files"}],default:"abort"});l==="abort"&&(a.fail("Aborting installation..."),process.exit(1)),await st({message:`Are you sure you want to ${l==="clear"?"clear the directory":"overwrite conflicting files"}`,default:!1})||(a.fail("Aborting installation..."),process.exit(1)),l==="clear"&&(a.info(`Emptying ${I.cyan.bold(e)} and creating tnt app...
|
53
|
+
`),O.emptyDirSync(n))}a.start(),O.copySync(t,n),O.renameSync(W.join(n,"_gitignore"),W.join(n,".gitignore"));let i=e==="."?"App":I.cyan.bold(e);a.succeed(`${i} ${I.green.bold("scaffolded successfully!")}
|
54
|
+
`)}import v from"path";import B from"fs-extra";function Pe({packages:e,projectDir:n}){let o=v.join(p,"template/packages/src/app/layout"),s=e.payload.inUse,a=v.join(o,"base.tsx"),i=v.join(n,`src/app/${s?"(frontend)":""}/layout.tsx`);B.copySync(a,i)}function _e({packages:e,projectDir:n}){let o=v.join(p,"template/packages/src/app/page"),s=e.authjs.inUse,t=e.payload.inUse,a="base.tsx";t&&(a="with-payload.tsx"),s&&(a="with-authjs.tsx");let i=v.join(o,a),l=v.join(n,`src/app/${t?"(frontend)":""}/page.tsx`);B.copySync(i,l)}function Se({packages:e,projectDir:n}){let o=v.join(p,"template/packages/src/app/globals"),s=e.payload.inUse,a=v.join(o,"base.css"),i=v.join(n,`src/app/${s?"(frontend)":""}/globals.css`);B.copySync(a,i)}async function xe({projectName:e,scopedAppName:n,packages:o,noInstall:s,databaseProvider:t}){let a=h(),i=lt.resolve(process.cwd(),e);return await we({projectName:e,projectDir:i,pkgManager:a,scopedAppName:n,noInstall:s,databaseProvider:t}),ke({projectName:e,scopedAppName:n,projectDir:i,pkgManager:a,packages:o,noInstall:s,databaseProvider:t}),Pe({packages:o,projectDir:i}),_e({packages:o,projectDir:i}),Se({packages:o,projectDir:i}),i}import{execSync as z}from"child_process";import V from"path";import{confirm as Ie}from"@inquirer/prompts";import T from"chalk";import{execa as D}from"execa";import Ae from"fs-extra";import pt from"ora";function ct(e){try{return z("git --version",{cwd:e}),!0}catch{return!1}}function K(e){return Ae.existsSync(V.join(e,".git"))}async function H(e){try{return await D("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}}function mt(){let n=z("git --version").toString().trim().split(" ")[2],o=n?.split(".")[0],s=n?.split(".")[1];return{major:Number(o),minor:Number(s)}}function dt(){return z("git config --global init.defaultBranch || echo main").toString().trim()}async function je(e){if(r.info("Initializing Git..."),!ct(e)){r.warn("Git is not installed. Skipping Git initialization.");return}let n=pt(`Creating a new git repo...
|
55
|
+
`).start(),o=K(e),s=await H(e),t=V.parse(e).name;if(s&&o){if(n.stop(),!await Ie({message:`${T.redBright.bold("Warning:")} Git is already initialized in "${t}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,default:!1})){n.info("Skipping Git initialization.");return}Ae.removeSync(V.join(e,".git"))}else if(s&&!o&&(n.stop(),!await Ie({message:`${T.redBright.bold("Warning:")} "${t}" is already in a git worktree. Would you still like to initialize a new git repository in this directory?`,default:!1}))){n.info("Skipping Git initialization.");return}try{let a=dt(),{major:i,minor:l}=mt();i<2||i==2&&l<28?(await D("git",["init"],{cwd:e}),await D("git",["symbolic-ref","HEAD",`refs/heads/${a}`],{cwd:e})):await D("git",["init",`--initial-branch=${a}`],{cwd:e}),await D("git",["add","."],{cwd:e}),n.succeed(`${T.green("Successfully initialized and staged")} ${T.green.bold("git")}
|
56
|
+
`)}catch{n.fail(`${T.bold.red("Failed:")} could not initialize git. Update git to the latest version!
|
57
|
+
`)}}import ft from"chalk";import{execa as Ce}from"execa";import Oe from"ora";var Y=async(e,n,o)=>{let{onDataHandle:s,args:t=["install"],stdout:a="pipe"}=o,i=Oe(`Running ${n} install...`).start(),l=Ce(n,t,{cwd:e,stdout:a});return await new Promise((d,g)=>{s&&l.stdout?.on("data",s(i)),l.on("error",u=>g(u)),l.on("close",()=>d())}),i},gt=async(e,n)=>{switch(e){case"npm":return await Ce(e,["install"],{cwd:n,stderr:"inherit"}),null;case"pnpm":return Y(n,e,{onDataHandle:o=>s=>{let t=s.toString();t.includes("Progress")&&(o.text=t.includes("|")?t.split(" | ")[1]??"":t)}});case"yarn":return Y(n,e,{onDataHandle:o=>s=>{o.text=s.toString()}});case"bun":return Y(n,e,{stdout:"ignore"})}},Te=async({projectDir:e})=>{r.info("Installing dependencies...");let n=h();(await gt(n,e)??Oe()).succeed(ft.green(`Successfully installed dependencies!
|
58
|
+
`))};var De=async({projectName:e=j,packages:n,noInstall:o,projectDir:s,databaseProvider:t})=>{let a=h();r.info("Next steps:"),e!=="."&&r.info(` cd ${e}`),o&&(a==="yarn"?r.info(` ${a}`):r.info(` ${a} install`)),["postgresql","mysql"].includes(t)&&r.info(" Add your database connection string to .env"),n?.authjs.inUse&&r.info(" Fill in your .env with necessary values. See https://create.tntstack.org/first-steps for more info."),["npm"].includes(a)?r.info(` ${a} run dev`):r.info(` ${a} dev`),!await H(s)&&!K(s)&&r.info(" git init"),r.info(' git commit -m "initial commit"')};import $ from"fs";import ut from"path";function Me(e,n,o){$.readdirSync(e).forEach(t=>{let a=ut.join(e,t);if($.statSync(a).isDirectory())Me(a,n,o);else{let l=$.readFileSync(a,"utf8").replace(new RegExp(n,"g"),o);$.writeFileSync(a,l,"utf8")}})}function Re(e,n){let o=n.replace(/\*/g,"").replace(/[^\/]$/,"$&/");Me(e,"@/",o)}import Ee from"path";function Ne(e){let o=N(e).split("/"),s=o[o.length-1];if(s==="."){let i=Ee.resolve(process.cwd());s=Ee.basename(i)}let t=o.findIndex(i=>i.startsWith("@"));o.findIndex(i=>i.startsWith("@"))!==-1&&(s=o.slice(t).join("/"));let a=o.filter(i=>!i.startsWith("@")).join("/");return[s,a]}import yt from"gradient-string";var ht={magenta:"#765bc8",pink:"#a48897",yellow:"#c7b561",green:"#8bb8a0",blue:"#4b97d5",cyan:"#22b6d2"};function $e(){let e=yt(Object.values(ht)),n=h();(n==="yarn"||n==="pnpm")&&console.log(""),console.log(e.multiline(Z))}import{execSync as bt}from"child_process";import vt from"https";function Ge(e){let n=A();n.includes("beta")?(r.warn(" You are using a beta version of create-tnt-stack."),r.warn(" Please report any bugs you encounter.")):n!==e&&(r.warn(" You are using an outdated version of create-tnt-stack."),r.warn(" Your version:",n+".","Latest version in the npm registry:",e),r.warn(" Please run the CLI with @latest to get the latest updates.")),console.log("")}function kt(){return new Promise((e,n)=>{vt.get("https://registry.npmjs.org/-/package/tnt-stack/dist-tags",o=>{if(o.statusCode===200){let s="";o.on("data",t=>s+=t),o.on("end",()=>{e(JSON.parse(s).latest)})}else n()}).on("error",()=>{n()})})}var Ue=()=>kt().catch(()=>{try{return bt("npm view create-tnt-stack version").toString().trim()}catch{return null}});async function Pt(){let e=await Ue(),n=h();$e(),e&&Ge(e);let{appName:o,packages:s,flags:{noGit:t,noInstall:a,importAlias:i},databaseProvider:l}=await be(),d=ge(s),[g,u]=Ne(o),m=await xe({projectName:u,scopedAppName:g,packages:d,noInstall:a,databaseProvider:l}),b=Le.readJsonSync(Fe.join(m,"package.json"));b.name=g,b.ctntaMetadata={initVersion:A()};let{stdout:_}=await wt(n,["-v"],{cwd:m});b.packageManager=`${n}@${_.trim()}`,Le.writeJSONSync(Fe.join(m,"package.json"),b,{spaces:2}),i!=="@/"&&Re(m,i),a||await Te({projectDir:m}),t||await je(m),await De({projectDir:m,projectName:u,packages:d,noInstall:a,databaseProvider:l}),process.exit(0)}Pt().catch(e=>{r.error("Aborting installation..."),e instanceof Error?r.error(e.message):(r.error("An unknown error occurred. Please open an issue on GitHub with the below:"),console.error(e)),process.exit(1)});
|
package/package.json
CHANGED
@@ -1,88 +1,88 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
2
|
+
"name": "create-tnt-stack",
|
3
|
+
"version": "0.5.0",
|
4
|
+
"description": "Create web application with the TNT-Powered stack",
|
5
|
+
"license": "MIT",
|
6
|
+
"repository": {
|
7
|
+
"type": "git",
|
8
|
+
"url": "https://github.com/slickyeet/create-tnt-stack",
|
9
|
+
"directory": "cli"
|
10
|
+
},
|
11
|
+
"keywords": [
|
12
|
+
"create-tnt-stack",
|
13
|
+
"tnt-stack",
|
14
|
+
"typescript",
|
15
|
+
"next.js",
|
16
|
+
"tailwind"
|
17
|
+
],
|
18
|
+
"type": "module",
|
19
|
+
"exports": "./dist/index.js",
|
20
|
+
"bin": {
|
21
|
+
"create-tnt-stack": "./dist/index.js"
|
22
|
+
},
|
23
|
+
"files": [
|
24
|
+
"dist",
|
25
|
+
"template",
|
26
|
+
"README.md",
|
27
|
+
"LICENSE",
|
28
|
+
"package.json"
|
29
|
+
],
|
30
|
+
"engines": {
|
31
|
+
"node": ">=18"
|
32
|
+
},
|
33
|
+
"scripts": {
|
34
|
+
"dev": "tsup --watch",
|
35
|
+
"build": "tsup",
|
36
|
+
"start": "node dist/index.js",
|
37
|
+
"format": "prettier '**/*.{cjs,mjs,ts,tsx,md,json}' --ignore-path ../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
|
38
|
+
"format:check": "prettier '**/*.{cjs,mjs,ts,tsx,md,json}' --ignore-path ../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --check",
|
39
|
+
"typecheck": "tsc",
|
40
|
+
"clean": "rm -rf dist .turbo node_modules",
|
41
|
+
"release": "changeset version",
|
42
|
+
"pub:beta": "bun run build && npm publish --tag beta",
|
43
|
+
"pub:release": "bun run build && npm publish"
|
44
|
+
},
|
45
|
+
"dependencies": {
|
46
|
+
"@inquirer/prompts": "^7.4.0",
|
47
|
+
"chalk": "^5.4.1",
|
48
|
+
"commander": "^13.1.0",
|
49
|
+
"execa": "^9.5.2",
|
50
|
+
"fs-extra": "^11.3.0",
|
51
|
+
"gradient-string": "^3.0.0",
|
52
|
+
"ora": "^8.2.0",
|
53
|
+
"sort-package-json": "^3.0.0"
|
54
|
+
},
|
55
|
+
"devDependencies": {
|
56
|
+
"@auth/prisma-adapter": "^2.8.0",
|
57
|
+
"@eslint/eslintrc": "^3.3.1",
|
58
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
59
|
+
"@payloadcms/db-sqlite": "^3.33.0",
|
60
|
+
"@payloadcms/db-vercel-postgres": "^3.33.0",
|
61
|
+
"@payloadcms/next": "^3.33.0",
|
62
|
+
"@payloadcms/payload-cloud": "^3.33.0",
|
63
|
+
"@payloadcms/richtext-lexical": "^3.33.0",
|
64
|
+
"@prisma/client": "^6.5.0",
|
65
|
+
"@t3-oss/env-nextjs": "^0.12.0",
|
66
|
+
"@types/fs-extra": "^11.0.4",
|
67
|
+
"@types/node": "^22",
|
68
|
+
"@types/react": "^19",
|
69
|
+
"@types/react-dom": "^19",
|
70
|
+
"eslint": "^9.22.0",
|
71
|
+
"eslint-config-next": "^15.2.4",
|
72
|
+
"graphql": "^16.10.0",
|
73
|
+
"next": "^15.2.4",
|
74
|
+
"next-auth": "^5.0.0-beta.25",
|
75
|
+
"payload": "^3.33.0",
|
76
|
+
"prettier": "^3.5.3",
|
77
|
+
"prettier-plugin-tailwindcss": "^0.6.11",
|
78
|
+
"prisma": "^6.5.0",
|
79
|
+
"react": "^19.0.0",
|
80
|
+
"react-dom": "^19.0.0",
|
81
|
+
"sharp": "^0.34.1",
|
82
|
+
"tailwindcss": "^4.0.17",
|
83
|
+
"tsup": "^8.4.0",
|
84
|
+
"type-fest": "^4.37.0",
|
85
|
+
"typescript": "^5.8.2",
|
86
|
+
"zod": "^3.24.2"
|
87
|
+
}
|
88
88
|
}
|
package/template/base/README.md
CHANGED
@@ -33,7 +33,7 @@ please refer to the respective docs.
|
|
33
33
|
|
34
34
|
- [Next.js](https://nextjs.org)
|
35
35
|
- [Payload CMS](https://payloadcms.com)
|
36
|
-
- [
|
36
|
+
- [Auth.js](https://authjs.dev/)
|
37
37
|
- [Prisma](https://prisma.io)
|
38
38
|
- [Drizzle](https://orm.drizzle.team)
|
39
39
|
- [Tailwind CSS](https://tailwindcss.com)
|
@@ -9,8 +9,8 @@ datasource db {
|
|
9
9
|
provider = "sqlite"
|
10
10
|
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
|
11
11
|
// Further reading:
|
12
|
-
// https://
|
13
|
-
// https://www.prisma.io/docs/
|
12
|
+
// https://authjs.dev/getting-started/adapters/prisma#schema
|
13
|
+
// https://www.prisma.io/docs/orm/reference/prisma-schema-reference#string
|
14
14
|
url = env("DATABASE_URL")
|
15
15
|
}
|
16
16
|
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import { fileURLToPath } from "url"
|
2
|
+
|
3
|
+
import { auth, signIn, signOut } from "@/server/auth"
|
4
|
+
|
5
|
+
export default async function HomePage() {
|
6
|
+
const session = await auth()
|
7
|
+
const user = session?.user
|
8
|
+
|
9
|
+
const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`
|
10
|
+
|
11
|
+
return (
|
12
|
+
<main className="mx-auto flex h-screen max-w-5xl flex-col items-center justify-between overflow-hidden p-6 sm:p-[45px]">
|
13
|
+
<header className="ml-auto">
|
14
|
+
{user ? (
|
15
|
+
<button
|
16
|
+
onClick={async () => {
|
17
|
+
"use server"
|
18
|
+
await signOut()
|
19
|
+
}}
|
20
|
+
className="cursor-pointer rounded-md bg-rose-400 px-4 py-2"
|
21
|
+
>
|
22
|
+
Sign Out
|
23
|
+
</button>
|
24
|
+
) : (
|
25
|
+
<button
|
26
|
+
onClick={async () => {
|
27
|
+
"use server"
|
28
|
+
await signIn("discord")
|
29
|
+
}}
|
30
|
+
className="cursor-pointer rounded-md bg-purple-400 px-4 py-2"
|
31
|
+
>
|
32
|
+
Sign In
|
33
|
+
</button>
|
34
|
+
)}
|
35
|
+
</header>
|
36
|
+
|
37
|
+
<div className="flex grow flex-col items-center justify-center">
|
38
|
+
{/* Logo */}
|
39
|
+
<picture className="relative">
|
40
|
+
<div className="absolute inset-0 animate-pulse rounded-xl bg-gradient-to-r from-purple-500 to-cyan-500 opacity-20 blur-xl dark:from-purple-800 dark:to-cyan-800" />
|
41
|
+
<source srcSet="https://github.com/SlickYeet/create-tnt-stack/blob/main/docs/public/logo.light.png?raw=true" />
|
42
|
+
<img
|
43
|
+
src="https://github.com/SlickYeet/create-tnt-stack/blob/main/docs/public/logo.light.png?raw=true"
|
44
|
+
alt="Logo"
|
45
|
+
width={65}
|
46
|
+
height={65}
|
47
|
+
className="block h-auto max-w-full"
|
48
|
+
/>
|
49
|
+
</picture>
|
50
|
+
|
51
|
+
<h1 className="mt-6 bg-gradient-to-r from-purple-500 to-cyan-500 bg-clip-text text-center text-4xl leading-10 text-transparent sm:text-5xl sm:leading-14 md:text-6xl md:leading-20 lg:mt-10 lg:text-7xl lg:font-bold">
|
52
|
+
TNT-Powered Next.js App
|
53
|
+
</h1>
|
54
|
+
<p className="mt-4 text-center text-lg text-neutral-700 md:text-xl lg:mt-6 dark:text-neutral-300">
|
55
|
+
Build modern web applications with today's most popular tools
|
56
|
+
</p>
|
57
|
+
|
58
|
+
<div className="mt-12 flex items-center gap-3">
|
59
|
+
<a
|
60
|
+
href="https://create.tntstack.org"
|
61
|
+
target="_blank"
|
62
|
+
rel="noopener noreferrer"
|
63
|
+
className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
|
64
|
+
>
|
65
|
+
Website
|
66
|
+
<svg
|
67
|
+
xmlns="http://www.w3.org/2000/svg"
|
68
|
+
viewBox="0 0 24 24"
|
69
|
+
strokeLinecap="round"
|
70
|
+
strokeLinejoin="round"
|
71
|
+
className="mb-1.5 size-4 fill-none stroke-current stroke-2"
|
72
|
+
>
|
73
|
+
<path d="M7 7h10v10" />
|
74
|
+
<path d="M7 17 17 7" />
|
75
|
+
</svg>
|
76
|
+
</a>
|
77
|
+
<a
|
78
|
+
href="https://create.tntstack.org/introduction"
|
79
|
+
target="_blank"
|
80
|
+
rel="noopener noreferrer"
|
81
|
+
className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
|
82
|
+
>
|
83
|
+
Docs
|
84
|
+
<svg
|
85
|
+
xmlns="http://www.w3.org/2000/svg"
|
86
|
+
viewBox="0 0 24 24"
|
87
|
+
strokeLinecap="round"
|
88
|
+
strokeLinejoin="round"
|
89
|
+
className="mb-1.5 size-4 fill-none stroke-current stroke-2"
|
90
|
+
>
|
91
|
+
<path d="M7 7h10v10" />
|
92
|
+
<path d="M7 17 17 7" />
|
93
|
+
</svg>
|
94
|
+
</a>
|
95
|
+
<a
|
96
|
+
href="https://github.com/SlickYeet/create-tnt-stack"
|
97
|
+
target="_blank"
|
98
|
+
rel="noopener noreferrer"
|
99
|
+
className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
|
100
|
+
>
|
101
|
+
GitHub
|
102
|
+
<svg
|
103
|
+
xmlns="http://www.w3.org/2000/svg"
|
104
|
+
viewBox="0 0 24 24"
|
105
|
+
strokeLinecap="round"
|
106
|
+
strokeLinejoin="round"
|
107
|
+
className="mb-1.5 size-4 fill-none stroke-current stroke-2"
|
108
|
+
>
|
109
|
+
<path d="M7 7h10v10" />
|
110
|
+
<path d="M7 17 17 7" />
|
111
|
+
</svg>
|
112
|
+
</a>
|
113
|
+
</div>
|
114
|
+
</div>
|
115
|
+
<div className="flex flex-col items-center gap-1 text-sm text-neutral-600 lg:flex-row lg:gap-2 dark:text-neutral-400">
|
116
|
+
<p className="m-0">Get started by editing </p>
|
117
|
+
<a
|
118
|
+
href={fileURL}
|
119
|
+
className="rounded-md bg-neutral-200 px-2 py-1 dark:bg-neutral-800"
|
120
|
+
>
|
121
|
+
<code>src/app/page.tsx</code>
|
122
|
+
</a>
|
123
|
+
</div>
|
124
|
+
</main>
|
125
|
+
)
|
126
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { PrismaAdapter } from "@auth/prisma-adapter"
|
2
|
+
import { NextAuthConfig } from "next-auth"
|
3
|
+
import Discord from "next-auth/providers/discord"
|
4
|
+
|
5
|
+
import { env } from "@/env"
|
6
|
+
import { db } from "@/server/db"
|
7
|
+
|
8
|
+
/**
|
9
|
+
* This is the Auth.js configuration for the application.
|
10
|
+
*
|
11
|
+
* @see https://authjs.dev/getting-started/installation
|
12
|
+
*/
|
13
|
+
export const authConfig: NextAuthConfig = {
|
14
|
+
adapter: PrismaAdapter(db),
|
15
|
+
providers: [
|
16
|
+
Discord({
|
17
|
+
clientId: env.DISCORD_CLIENT_ID,
|
18
|
+
clientSecret: env.DISCORD_CLIENT_SECRET,
|
19
|
+
}),
|
20
|
+
/**
|
21
|
+
* ...add more providers here.
|
22
|
+
*
|
23
|
+
* Most other providers require a bit more work than the Discord provider. For example, the
|
24
|
+
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
|
25
|
+
* model. Refer to the Auth.js docs for the provider you want to use. Example:
|
26
|
+
*
|
27
|
+
* @see https://authjs.dev/getting-started/providers/github
|
28
|
+
*/
|
29
|
+
],
|
30
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { NextAuthConfig } from "next-auth"
|
2
|
+
import Discord from "next-auth/providers/discord"
|
3
|
+
|
4
|
+
import { env } from "@/env"
|
5
|
+
|
6
|
+
/**
|
7
|
+
* This is the Auth.js configuration for the application.
|
8
|
+
*
|
9
|
+
* @see https://authjs.dev/getting-started/installation
|
10
|
+
*/
|
11
|
+
export const authConfig: NextAuthConfig = {
|
12
|
+
providers: [
|
13
|
+
Discord({
|
14
|
+
clientId: env.DISCORD_CLIENT_ID,
|
15
|
+
clientSecret: env.DISCORD_CLIENT_SECRET,
|
16
|
+
}),
|
17
|
+
/**
|
18
|
+
* ...add more providers here.
|
19
|
+
*
|
20
|
+
* Most other providers require a bit more work than the Discord provider. For example, the
|
21
|
+
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
|
22
|
+
* model. Refer to the Auth.js docs for the provider you want to use. Example:
|
23
|
+
*
|
24
|
+
* @see https://authjs.dev/getting-started/providers/github
|
25
|
+
*/
|
26
|
+
],
|
27
|
+
}
|
@@ -1,60 +0,0 @@
|
|
1
|
-
import { PrismaAdapter } from "@auth/prisma-adapter"
|
2
|
-
import { type DefaultSession, type NextAuthOptions } from "next-auth"
|
3
|
-
import DiscordProvider from "next-auth/providers/discord"
|
4
|
-
|
5
|
-
import { env } from "@/env"
|
6
|
-
import { db } from "@/server/db"
|
7
|
-
|
8
|
-
/**
|
9
|
-
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
|
10
|
-
* object and keep type safety.
|
11
|
-
*
|
12
|
-
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
|
13
|
-
*/
|
14
|
-
declare module "next-auth" {
|
15
|
-
interface Session extends DefaultSession {
|
16
|
-
user: {
|
17
|
-
id: string
|
18
|
-
// ...other properties
|
19
|
-
// role: UserRole;
|
20
|
-
} & DefaultSession["user"]
|
21
|
-
}
|
22
|
-
|
23
|
-
// interface User {
|
24
|
-
// // ...other properties
|
25
|
-
// // role: UserRole;
|
26
|
-
// }
|
27
|
-
}
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
|
31
|
-
*
|
32
|
-
* @see https://next-auth.js.org/configuration/options
|
33
|
-
*/
|
34
|
-
export const authConfig = {
|
35
|
-
providers: [
|
36
|
-
DiscordProvider({
|
37
|
-
clientId: env.DISCORD_CLIENT_ID,
|
38
|
-
clientSecret: env.DISCORD_CLIENT_SECRET,
|
39
|
-
}),
|
40
|
-
/**
|
41
|
-
* ...add more providers here.
|
42
|
-
*
|
43
|
-
* Most other providers require a bit more work than the Discord provider. For example, the
|
44
|
-
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
|
45
|
-
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
|
46
|
-
*
|
47
|
-
* @see https://next-auth.js.org/providers/github
|
48
|
-
*/
|
49
|
-
],
|
50
|
-
adapter: PrismaAdapter(db),
|
51
|
-
callbacks: {
|
52
|
-
session: ({ session, user }) => ({
|
53
|
-
...session,
|
54
|
-
user: {
|
55
|
-
...session.user,
|
56
|
-
id: user.id,
|
57
|
-
},
|
58
|
-
}),
|
59
|
-
},
|
60
|
-
} satisfies NextAuthOptions
|
@@ -1,57 +0,0 @@
|
|
1
|
-
import { type DefaultSession, type NextAuthOptions } from "next-auth"
|
2
|
-
import DiscordProvider from "next-auth/providers/discord"
|
3
|
-
|
4
|
-
import { env } from "@/env"
|
5
|
-
|
6
|
-
/**
|
7
|
-
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
|
8
|
-
* object and keep type safety.
|
9
|
-
*
|
10
|
-
* @see https://next-auth.js.org/getting-started/typescript#module-augmentation
|
11
|
-
*/
|
12
|
-
declare module "next-auth" {
|
13
|
-
interface Session extends DefaultSession {
|
14
|
-
user: {
|
15
|
-
id: string
|
16
|
-
// ...other properties
|
17
|
-
// role: UserRole;
|
18
|
-
} & DefaultSession["user"]
|
19
|
-
}
|
20
|
-
|
21
|
-
// interface User {
|
22
|
-
// // ...other properties
|
23
|
-
// // role: UserRole;
|
24
|
-
// }
|
25
|
-
}
|
26
|
-
|
27
|
-
/**
|
28
|
-
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
|
29
|
-
*
|
30
|
-
* @see https://next-auth.js.org/configuration/options
|
31
|
-
*/
|
32
|
-
export const authConfig = {
|
33
|
-
providers: [
|
34
|
-
DiscordProvider({
|
35
|
-
clientId: env.DISCORD_CLIENT_ID,
|
36
|
-
clientSecret: env.DISCORD_CLIENT_SECRET,
|
37
|
-
}),
|
38
|
-
/**
|
39
|
-
* ...add more providers here.
|
40
|
-
*
|
41
|
-
* Most other providers require a bit more work than the Discord provider. For example, the
|
42
|
-
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
|
43
|
-
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
|
44
|
-
*
|
45
|
-
* @see https://next-auth.js.org/providers/github
|
46
|
-
*/
|
47
|
-
],
|
48
|
-
callbacks: {
|
49
|
-
session: ({ session, token }) => ({
|
50
|
-
...session,
|
51
|
-
user: {
|
52
|
-
...session.user,
|
53
|
-
id: token.sub,
|
54
|
-
},
|
55
|
-
}),
|
56
|
-
},
|
57
|
-
} satisfies NextAuthOptions
|
@@ -1,10 +0,0 @@
|
|
1
|
-
import NextAuth from "next-auth"
|
2
|
-
import { cache } from "react"
|
3
|
-
|
4
|
-
import { authConfig } from "./config"
|
5
|
-
|
6
|
-
const { auth: uncachedAuth, handlers, signIn, signOut } = NextAuth(authConfig)
|
7
|
-
|
8
|
-
const auth = cache(uncachedAuth)
|
9
|
-
|
10
|
-
export { auth, handlers, signIn, signOut }
|
File without changes
|
File without changes
|