zerostarter 0.0.6 → 0.0.8-canary.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/dist/bin/index.d.mts +1 -0
- package/dist/bin/index.mjs +33 -0
- package/dist/convert-BzMTXW9D.mjs +110 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +1 -0
- package/package.json +20 -128
- package/LICENSE.md +0 -21
- package/README.md +0 -274
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{n as e,t}from"../convert-BzMTXW9D.mjs";import{basename as n,join as r,resolve as i}from"node:path";import{existsSync as a,readdirSync as o}from"node:fs";import{createInterface as s}from"node:readline/promises";import{parseArgs as c}from"node:util";import{execFileSync as l}from"node:child_process";var u={name:`zerostarter`,version:`0.0.8-canary.0`,description:`Go from zero to a production-ready SaaS, rebranded and ready to ship.`,keywords:[`cli`,`saas`,`scaffold`,`starter`,`template`,`zerostarter`],homepage:`https://github.com/nrjdalal/zerostarter#readme`,bugs:`https://github.com/nrjdalal/zerostarter/issues`,license:`MIT`,author:{name:`Neeraj Dalal`,email:`admin@nrjdalal.com`,url:`https://nrjdalal.com`},repository:`nrjdalal/zerostarter`,funding:`https://github.com/sponsors/nrjdalal`,bin:{zerostarter:`dist/bin/index.mjs`},files:[`dist`],type:`module`,types:`./dist/index.d.mts`,exports:`./dist/index.mjs`,scripts:{build:`tsdown`,"check-types":`tsc --noEmit`,dev:`tsdown --watch`,test:`bun test`},devDependencies:{"@packages/config":`workspace:*`,"@types/bun":`catalog:`,"@types/node":`catalog:`,tsdown:`catalog:`,typescript:`catalog:`}};const d=()=>!!(process.stdin.isTTY&&process.stdout.isTTY),f=(e,t=e)=>process.stdout.isTTY?`\x1b]8;;${e}\x07${t}\x1b]8;;\x07`:e,p=(e,t=process.stdout)=>n=>t.isTTY?`\x1b[${e}m${n}\x1b[0m`:n,m=p(`38;5;208`),h=p(`38;2;63;185;80`),g=p(`38;2;210;153;34`),_=p(`38;2;248;81;73`,process.stderr),v=async(e,t=``)=>{let n=s({input:process.stdin,output:process.stdout});try{return(await n.question(`${e}${t?` (${t})`:``}: `)).trim()||t}finally{n.close()}},y=async(e,t=!0)=>{let n=s({input:process.stdin,output:process.stdout});try{let r=(await n.question(`${e} (${t?`Y/n`:`y/N`}) `)).trim().toLowerCase();return r?r===`y`||r===`yes`:t}finally{n.close()}},b=(e,t,n)=>l(e,t,{cwd:n,encoding:`utf8`,stdio:[`ignore`,`pipe`,`pipe`]}),x=(e,t=`main`)=>{b(`bunx`,[`gitpick@5.4.1`,`https://github.com/nrjdalal/zerostarter/tree/${t}`,e])},S=e=>{b(`bun`,[`install`],e)},C=e=>{b(`git`,[`init`,`-q`],e)},w=(e,t)=>{b(`git`,[`add`,`-A`],e);try{b(`git`,[`commit`,`--no-verify`,`-q`,`-m`,t],e)}catch{}},T=e=>!a(e)||o(e).filter(e=>e!==`.git`).length===0,E=t=>e(r(t,`packages/config/src/site.ts`)),D=async a=>{let{positionals:o,values:s}=c({allowPositionals:!0,args:a,options:{"dry-run":{type:`boolean`},help:{short:`h`,type:`boolean`},yes:{short:`y`,type:`boolean`}}});if(s.help){console.log(`Usage:
|
|
3
|
+
$ zerostarter init [dir] [options]
|
|
4
|
+
|
|
5
|
+
Scaffold ZeroStarter into dir (default .) as a fresh product. The author's
|
|
6
|
+
content, public assets, and agent skills are left out for you to supply; the
|
|
7
|
+
dir name becomes the project name and site.ts + package.json are rebranded. If
|
|
8
|
+
the dir already holds a ZeroStarter clone it is used in place; otherwise the
|
|
9
|
+
latest ZeroStarter is fetched into it first.
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-y, --yes Skip prompts; fail instead of prompting when input is needed
|
|
13
|
+
--dry-run Print the plan without writing anything
|
|
14
|
+
-h, --help Display help`);return}let l=d()&&!s.yes,u=o[0]??`.`,f=i(u),p=E(f);if(!p&&!T(f)){if(!l)throw Error(`Target directory is not empty. Pass an empty target dir, for example: zerostarter init my-product`);let e=await v(`Target directory is not empty. New project directory`);if(!e)throw Error(`No directory name provided.`);u=e}let _=i(u),b=n(_),D={name:b};if(s[`dry-run`]){console.log(`zerostarter init (dry run)`),console.log(` target: ${_}`),console.log(` name: ${b}`),console.log(` mode: ${E(_)?`in place`:`fetch first`}`);return}if(p&&l&&!await y(g(`Convert ${_} in place? This rewrites files and commits.`),!1)){console.log(`Aborted.`);return}E(_)||(console.log(`Fetching the latest ZeroStarter ...`),x(_)),e(r(_,`.git`))||(C(_),w(_,`chore: scaffold from zerostarter`)),console.log(`Removing starter content and rebranding ...`),t(_,D),console.log(`Installing dependencies ...`),S(_),w(_,`chore: re-baseline as ${b}`);let O=[[`packages/config/src/site.ts`,`your brand: name, tagline, links`],[`web/next/content`,`your docs and blog`],[`web/next/public`,`your logo and assets`]];console.log(`\n${h(`✓`)} ${b} is ready.\n`),console.log(`Next steps:`),_!==process.cwd()&&console.log(` ${m(`cd ${u}`)}`),console.log(` ${m(`cp .env.example .env`)} # add your secrets`),console.log(` ${m(`bun dev`)}`),console.log(`
|
|
15
|
+
Make it yours:`);for(let[e,t]of O)console.log(` ${e.padEnd(29)} ${t}`)},O=async e=>{console.log(`zerostarter sync is not implemented yet.`),console.log(`Planned: a gitpick overlay of the latest zerostarter onto an existing fork, then a`),console.log(`prune of starter-only artifacts while preserving the fork's product and branding.`)},{author:k,name:A,version:j}=u,M=`Version:
|
|
16
|
+
${A}@${j}
|
|
17
|
+
|
|
18
|
+
Go from zero to a production-ready SaaS, rebranded and ready to ship.
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
$ ${A} <command> [options]
|
|
22
|
+
|
|
23
|
+
Commands:
|
|
24
|
+
init [dir] Scaffold ZeroStarter into dir (default .) as a fresh product.
|
|
25
|
+
The dir name becomes the project name.
|
|
26
|
+
sync Re-baseline an existing fork on ZeroStarter's latest scaffold
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
-v, --version Display version
|
|
30
|
+
-h, --help Display help
|
|
31
|
+
|
|
32
|
+
Author:
|
|
33
|
+
${k.name} <${k.email}> (${f(k.url)})`;(async()=>{try{let e=process.argv.slice(2),t=e[0],n=e.slice(1);switch(t){case`init`:return await D(n);case`sync`:return await O(n);case void 0:case`-h`:case`--help`:console.log(M);return;case`-v`:case`--version`:console.log(`${A}@${j}`);return;default:console.error(_(`Unknown command: ${t}\n`)),console.log(M),process.exit(1)}}catch(e){console.error(_(e instanceof Error?e.message:String(e))),process.exit(1)}})();export{};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import{dirname as e,join as t}from"node:path";import{existsSync as n,mkdirSync as r,readFileSync as i,rmSync as a,writeFileSync as o}from"node:fs";const s=e=>n(e),c=e=>i(e,`utf8`),l=(t,n)=>{r(e(t),{recursive:!0}),o(t,n)},u=e=>{a(e,{force:!0,recursive:!0})},d=e=>JSON.parse(c(e)),f=(e,t)=>{l(e,`${JSON.stringify(t,null,2)}\n`)},p=(e,t)=>{if(!n(e))return!1;let r=c(e),i=r;for(let[e,n]of t)i=i.split(e).join(n);return i===r?!1:(o(e,i),!0)},m=({name:e})=>{let t=e.charAt(0).toUpperCase()+e.slice(1);return`// Brand identity for this app: the single source a fork edits to rebrand. web reads it via lib/config.ts.
|
|
2
|
+
export const site = {
|
|
3
|
+
name: "${t}",
|
|
4
|
+
description: "${t} is just getting started. Tell its story here.",
|
|
5
|
+
tagline: "Your tagline, ready when you are.",
|
|
6
|
+
social: {
|
|
7
|
+
github: "",
|
|
8
|
+
x: "",
|
|
9
|
+
discord: "",
|
|
10
|
+
},
|
|
11
|
+
// Local-only dev agent identity (api/hono agents router).
|
|
12
|
+
agent: {
|
|
13
|
+
name: "LocalAgent",
|
|
14
|
+
email: "agent@local.host",
|
|
15
|
+
},
|
|
16
|
+
// Injectable long-form text blocks. A product sets its own, or leaves them empty.
|
|
17
|
+
apiReferenceDescription: "",
|
|
18
|
+
llmsFullPreamble: "",
|
|
19
|
+
} as const
|
|
20
|
+
|
|
21
|
+
export type Site = typeof site
|
|
22
|
+
`},h=()=>`import { redirect } from "next/navigation"
|
|
23
|
+
|
|
24
|
+
// Fresh fork: redirect to the waitlist until you build your real home page.
|
|
25
|
+
export default function Home() {
|
|
26
|
+
redirect("/waitlist")
|
|
27
|
+
}
|
|
28
|
+
`,g=()=>`# AGENTS.md
|
|
29
|
+
|
|
30
|
+
Guidance for AI coding agents working in this repository.
|
|
31
|
+
`,_=()=>`---
|
|
32
|
+
slug: /docs
|
|
33
|
+
title: Introduction
|
|
34
|
+
description: Documentation.
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Introduction
|
|
38
|
+
|
|
39
|
+
This is your documentation home. Start writing, this page is yours.
|
|
40
|
+
`,v=()=>`---
|
|
41
|
+
slug: /console/docs
|
|
42
|
+
title: Introduction
|
|
43
|
+
description: Internal documentation.
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Introduction
|
|
47
|
+
|
|
48
|
+
Your team's internal docs live here.
|
|
49
|
+
`,y=e=>`---
|
|
50
|
+
title: Blog
|
|
51
|
+
description: Latest articles and updates
|
|
52
|
+
createdAt: ${e}
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Recent Posts
|
|
56
|
+
|
|
57
|
+
<BlogPostList />
|
|
58
|
+
`,b=e=>`---
|
|
59
|
+
title: Hello World
|
|
60
|
+
description: The first post on your new blog.
|
|
61
|
+
createdAt: ${e}
|
|
62
|
+
publishedAt: ${e}
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Hello World
|
|
66
|
+
|
|
67
|
+
Your very first post. Replace it with something worth reading.
|
|
68
|
+
`,x=()=>`import type { DocsConfig } from "./src/lib/docs/types"
|
|
69
|
+
|
|
70
|
+
const docsConfig = {
|
|
71
|
+
docs: {
|
|
72
|
+
"Getting Started": [
|
|
73
|
+
{
|
|
74
|
+
"/docs": {
|
|
75
|
+
title: "Introduction",
|
|
76
|
+
description: "Documentation.",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
console: {
|
|
82
|
+
"Getting Started": [
|
|
83
|
+
{
|
|
84
|
+
"/console/docs": {
|
|
85
|
+
title: "Introduction",
|
|
86
|
+
description: "Internal documentation.",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
} satisfies DocsConfig
|
|
92
|
+
|
|
93
|
+
export default docsConfig
|
|
94
|
+
`,S=(e,...n)=>t(e,...n),C=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||`app`,w=[`web/next/content`,`web/next/public`,`.agents/skills`,`.claude/skills`,`.github/skills`],T=[`packages/cli`,`.github/workflows/cli-release.yml`,`.github/audit`,`.github/reviews`,`.infisical.json`,`.github/assets/graph-build.svg`,`.github/assets/cli.tape`,`.github/assets/setup.sh`,`.github/assets/cli.gif`,`.github/FUNDING.yml`,`LICENSE.md`,`CHANGELOG.md`,`bun.lock`,`skills-lock.json`,`web/next/src/app/hire`,`web/next/src/app/resume`,`web/next/src/fonts/caveat-latin-wght-normal.woff2`,`web/next/src/fonts/newsreader-latin-wght-normal.woff2`,`web/next/src/fonts/newsreader-latin-wght-italic.woff2`],E=e=>{let t=new Date,n=t.toISOString().slice(0,10),r=[t.getFullYear(),t.getMonth()+1,t.getDate()].map(e=>String(e).padStart(2,`0`)).join(`-`),i=r<n?r:n;l(S(e,`web/next/content/docs/index.mdx`),_()),l(S(e,`web/next/content/blog/index.mdx`),y(i)),l(S(e,`web/next/content/blog/hello-world.mdx`),b(i)),l(S(e,`web/next/content/console/docs/index.mdx`),v()),l(S(e,`web/next/docs.config.ts`),x()),l(S(e,`web/next/public/.gitkeep`),``),l(S(e,`web/next/src/app/page.tsx`),h()),l(S(e,`AGENTS.md`),g())},D=e=>{let t=p(S(e,`web/next/src/components/navbar/home.tsx`),[[` { href: "/hire", label: "Hire" },
|
|
95
|
+
`,``]]),n=p(S(e,`web/next/src/lib/fonts.ts`),[[`
|
|
96
|
+
export const caveat = localFont({
|
|
97
|
+
src: "../fonts/caveat-latin-wght-normal.woff2",
|
|
98
|
+
variable: "--font-caveat",
|
|
99
|
+
weight: "400 700",
|
|
100
|
+
})
|
|
101
|
+
`,``]]),r=p(S(e,`web/next/src/lib/fonts.ts`),[[`
|
|
102
|
+
export const newsreader = localFont({
|
|
103
|
+
src: [
|
|
104
|
+
{ path: "../fonts/newsreader-latin-wght-normal.woff2", style: "normal" },
|
|
105
|
+
{ path: "../fonts/newsreader-latin-wght-italic.woff2", style: "italic" },
|
|
106
|
+
],
|
|
107
|
+
variable: "--font-newsreader",
|
|
108
|
+
weight: "200 800",
|
|
109
|
+
})
|
|
110
|
+
`,``]]);if(!n||!r)throw Error(`fonts.ts: caveat/newsreader exports not found, but their woff2 files were removed (template drift). Update packages/cli/src/convert.ts.`);if(!t)throw Error(`navbar/home.tsx: /hire entry not found (template drift). Update packages/cli/src/convert.ts.`)},O=(e,t)=>{l(S(e,`packages/config/src/site.ts`),m(t));let n=S(e,`package.json`),r=d(n);r.name=C(t.name),r.version=`0.0.0`,delete r.homepage,delete r.bugs,delete r.license,delete r.author,delete r.repository,delete r.funding,f(n,r)},k=(e,t)=>{for(let t of[...w,...T])u(S(e,t));E(e),D(e),O(e,t)};export{s as n,k as t};
|
package/dist/index.d.mts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./convert-BzMTXW9D.mjs";export{e as convertRepo};
|
package/package.json
CHANGED
|
@@ -1,140 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zerostarter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8-canary.0",
|
|
4
|
+
"description": "Go from zero to a production-ready SaaS, rebranded and ready to ship.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"saas",
|
|
8
|
+
"scaffold",
|
|
9
|
+
"starter",
|
|
10
|
+
"template",
|
|
11
|
+
"zerostarter"
|
|
12
|
+
],
|
|
4
13
|
"homepage": "https://github.com/nrjdalal/zerostarter#readme",
|
|
5
14
|
"bugs": "https://github.com/nrjdalal/zerostarter/issues",
|
|
6
|
-
"repository": "nrjdalal/zerostarter",
|
|
7
|
-
"funding": "https://github.com/sponsors/nrjdalal",
|
|
8
15
|
"license": "MIT",
|
|
9
|
-
"files": [],
|
|
10
16
|
"author": {
|
|
11
17
|
"name": "Neeraj Dalal",
|
|
12
18
|
"email": "admin@nrjdalal.com",
|
|
13
19
|
"url": "https://nrjdalal.com"
|
|
14
20
|
},
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "turbo build --summarize",
|
|
22
|
-
"check-types": "SKIP_ENV_VALIDATION=true turbo check-types --summarize",
|
|
23
|
-
"clean": "bunx rimraf --glob \"**/.next\" \"**/.source\" \"**/.turbo\" \"**/dist\" \"**/node_modules\" && bunx delete-empty",
|
|
24
|
-
"db:generate": "turbo build --filter=@packages/* && bun --cwd packages/db drizzle-kit generate",
|
|
25
|
-
"db:migrate": "turbo build --filter=@packages/* && bun --cwd packages/db drizzle-kit migrate",
|
|
26
|
-
"db:studio": "turbo build --filter=@packages/* && bun --cwd packages/db drizzle-kit studio",
|
|
27
|
-
"predev": "turbo build --filter=@packages/*",
|
|
28
|
-
"dev": "turbo dev --ui tui",
|
|
29
|
-
"devtools": "turbo devtools",
|
|
30
|
-
"format": "prettier --write --ignore-unknown *",
|
|
31
|
-
"postinstall": "bun .github/scripts/deps-manager.ts",
|
|
32
|
-
"lint": "turbo lint --summarize",
|
|
33
|
-
"prepare": "bunx simple-git-hooks",
|
|
34
|
-
"start": "turbo start"
|
|
35
|
-
},
|
|
36
|
-
"simple-git-hooks": {
|
|
37
|
-
"pre-commit": "bunx lint-staged --verbose && bun run build",
|
|
38
|
-
"commit-msg": "bunx commitlint --edit $1"
|
|
39
|
-
},
|
|
40
|
-
"commitlint": {
|
|
41
|
-
"extends": [
|
|
42
|
-
"@commitlint/config-conventional"
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
|
-
"lint-staged": {
|
|
46
|
-
"*": [
|
|
47
|
-
"oxlint",
|
|
48
|
-
"prettier --write --ignore-unknown"
|
|
49
|
-
],
|
|
50
|
-
"package.json": [
|
|
51
|
-
"bun .github/scripts/deps-manager.ts",
|
|
52
|
-
"sort-package-json"
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
"prettier": {
|
|
56
|
-
"printWidth": 100,
|
|
57
|
-
"semi": false
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"@commitlint/cli": "catalog:",
|
|
61
|
-
"@commitlint/config-conventional": "catalog:",
|
|
62
|
-
"@ianvs/prettier-plugin-sort-imports": "catalog:",
|
|
63
|
-
"@octokit/rest": "catalog:",
|
|
64
|
-
"@types/bun": "catalog:",
|
|
65
|
-
"@types/node": "catalog:",
|
|
66
|
-
"globby": "catalog:",
|
|
67
|
-
"lint-staged": "catalog:",
|
|
68
|
-
"oxlint": "catalog:",
|
|
69
|
-
"prettier": "catalog:",
|
|
70
|
-
"prettier-plugin-tailwindcss": "catalog:",
|
|
71
|
-
"simple-git-hooks": "catalog:",
|
|
72
|
-
"sort-package-json": "catalog:",
|
|
73
|
-
"turbo": "catalog:"
|
|
21
|
+
"repository": "nrjdalal/zerostarter",
|
|
22
|
+
"funding": "https://github.com/sponsors/nrjdalal",
|
|
23
|
+
"bin": {
|
|
24
|
+
"zerostarter": "dist/bin/index.mjs"
|
|
74
25
|
},
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"@hono/zod-validator": "^0.7.6",
|
|
82
|
-
"@hookform/resolvers": "^5.2.2",
|
|
83
|
-
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
|
84
|
-
"@octokit/rest": "^22.0.1",
|
|
85
|
-
"@remixicon/react": "^4.7.0",
|
|
86
|
-
"@t3-oss/env-core": "^0.13.10",
|
|
87
|
-
"@tailwindcss/postcss": "^4.1.18",
|
|
88
|
-
"@tanstack/react-form": "^1.27.6",
|
|
89
|
-
"@tanstack/react-query": "^5.90.12",
|
|
90
|
-
"@tanstack/react-query-devtools": "^5.91.1",
|
|
91
|
-
"@types/bun": "latest",
|
|
92
|
-
"@types/mdx": "^2.0.13",
|
|
93
|
-
"@types/node": "latest",
|
|
94
|
-
"@types/react": "^19.2.1",
|
|
95
|
-
"@types/react-dom": "^19.2.1",
|
|
96
|
-
"babel-plugin-react-compiler": "^1.0.0",
|
|
97
|
-
"better-auth": "^1.4.9",
|
|
98
|
-
"class-variance-authority": "^0.7.1",
|
|
99
|
-
"clsx": "^2.1.1",
|
|
100
|
-
"cmdk": "^1.1.1",
|
|
101
|
-
"concurrently": "^9.2.1",
|
|
102
|
-
"date-fns": "^4.1.0",
|
|
103
|
-
"dotenv": "^17.2.3",
|
|
104
|
-
"drizzle-kit": "^0.31.8",
|
|
105
|
-
"drizzle-orm": "^0.45.1",
|
|
106
|
-
"embla-carousel-react": "^8.6.0",
|
|
107
|
-
"fumadocs-core": "^16.3.2",
|
|
108
|
-
"fumadocs-mdx": "^14.2.2",
|
|
109
|
-
"fumadocs-ui": "^16.3.2",
|
|
110
|
-
"globby": "^16.1.0",
|
|
111
|
-
"hono": "^4.11.1",
|
|
112
|
-
"input-otp": "^1.4.2",
|
|
113
|
-
"lint-staged": "^16.2.7",
|
|
114
|
-
"lucide-react": "^0.562.0",
|
|
115
|
-
"next": "^16.1.1",
|
|
116
|
-
"next-themes": "^0.4.6",
|
|
117
|
-
"oxlint": "^1.35.0",
|
|
118
|
-
"postgres": "^3.4.7",
|
|
119
|
-
"prettier": "^3.7.4",
|
|
120
|
-
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
121
|
-
"radix-ui": "^1.4.3",
|
|
122
|
-
"react": "^19.2.3",
|
|
123
|
-
"react-day-picker": "^9.13.0",
|
|
124
|
-
"react-dom": "^19.2.3",
|
|
125
|
-
"react-hook-form": "^7.69.0",
|
|
126
|
-
"react-resizable-panels": "^3.0.6",
|
|
127
|
-
"recharts": "2.15.4",
|
|
128
|
-
"simple-git-hooks": "^2.13.1",
|
|
129
|
-
"sonner": "^2.0.7",
|
|
130
|
-
"sort-package-json": "^3.6.0",
|
|
131
|
-
"tailwind-merge": "^3.4.0",
|
|
132
|
-
"tailwindcss": "^4.1.18",
|
|
133
|
-
"tsdown": "^0.18.2",
|
|
134
|
-
"turbo": "^2.7.1",
|
|
135
|
-
"tw-animate-css": "^1.4.0",
|
|
136
|
-
"typescript": "^5.9.3",
|
|
137
|
-
"vaul": "^1.1.2",
|
|
138
|
-
"zod": "^4.2.1"
|
|
139
|
-
}
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
31
|
+
"exports": "./dist/index.mjs"
|
|
140
32
|
}
|
package/LICENSE.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Neeraj Dalal
|
|
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/README.md
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
# ZeroStarter - The SaaS Starter
|
|
2
|
-
|
|
3
|
-
A modern, type-safe, and high-performance SaaS starter template built with a monorepo architecture.
|
|
4
|
-
|
|
5
|
-
- **📚 Documentation**: For comprehensive documentation, visit **[https://zerostarter.dev/docs](https://zerostarter.dev/docs)**.
|
|
6
|
-
- **🤖 AI/LLM Users**: For optimized documentation, use **[https://zerostarter.dev/llms.txt](https://zerostarter.dev/llms.txt)**.
|
|
7
|
-
- **🐦 X**: Follow **[@nrjdalal](https://twitter.com/nrjdalal)** for updates and don't forget to star the repository!
|
|
8
|
-
|
|
9
|
-
> [!IMPORTANT]
|
|
10
|
-
> **Release Candidate (RC) Status**: ZeroStarter is currently in **Release Candidate (RC)** status. All implemented features are stable and production-ready. We're actively adding new features and integrations day-by-day.
|
|
11
|
-
|
|
12
|
-
<!--
|
|
13
|
-
```bash
|
|
14
|
-
npx turbo run build --graph=graph.svg
|
|
15
|
-
sed -i '' 's/\[root\] //g; s/#build//g; s/___ROOT___/ZeroStarter/g' graph.svg
|
|
16
|
-
sed -i '' 's/fill="white"/fill="none"/g; s/fill="#ffffff"/fill="none"/g; s/fill="#fff"/fill="none"/g' graph.svg
|
|
17
|
-
sed -i '' 's/fill="black"/fill="#1f6feb"/g' graph.svg
|
|
18
|
-
sed -i '' 's/stroke="[^"]*"/stroke="#1f6feb"/g; s/stroke:[^;]*;/stroke:#1f6feb;/g' graph.svg
|
|
19
|
-
sed -i '' 's/<text\([^>]*\)>/<text\1 fill="#1f6feb">/g' graph.svg
|
|
20
|
-
sed -i '' 's/stroke="#1f6feb" points="-4,4/stroke="none" points="-4,4/g' graph.svg
|
|
21
|
-
mkdir -p .github/assets
|
|
22
|
-
mv graph.svg .github/assets/graph-build.svg
|
|
23
|
-
```
|
|
24
|
-
-->
|
|
25
|
-
|
|
26
|
-
## Architecture and Tech Stack
|
|
27
|
-
|
|
28
|
-

|
|
29
|
-
|
|
30
|
-
- **Runtime & Build System**: [Bun](https://bun.sh) + [Turborepo](https://turbo.build)
|
|
31
|
-
- **Frontend**: [Next.js 16](https://nextjs.org)
|
|
32
|
-
- **Backend**: [Hono](https://hono.dev)
|
|
33
|
-
- **RPC**: [Hono Client](https://hono.dev/docs/guides/rpc) for end-to-end type safety with frontend client
|
|
34
|
-
- **Database**: [PostgreSQL](https://www.postgresql.org) with [Drizzle ORM](https://orm.drizzle.team)
|
|
35
|
-
- **Authentication**: [Better Auth](https://better-auth.com)
|
|
36
|
-
- **Styling**: [Tailwind CSS](https://tailwindcss.com)
|
|
37
|
-
- **UI Components**: [Shadcn UI](https://ui.shadcn.com)
|
|
38
|
-
- **Data Fetching**: [TanStack Query](https://tanstack.com/query/latest)
|
|
39
|
-
- **Validation**: [Zod](https://zod.dev)
|
|
40
|
-
- **Bundling, Linting & Formatting**: [tsdown](https://tsdown.dev), [Oxlint](https://oxc.rs/docs/guide/usage/linter) and [Prettier](https://prettier.io)
|
|
41
|
-
- **Documentation**: [Fumadocs](https://fumadocs.dev) with auto-generated [llms.txt](https://zerostarter.dev/llms.txt)
|
|
42
|
-
- **Automated Releases**: Automatically updated [Changelog](https://github.com/nrjdalal/zerostarter/releases) on release
|
|
43
|
-
|
|
44
|
-
### Future Stack and Features
|
|
45
|
-
|
|
46
|
-
- **AI**
|
|
47
|
-
- [ ] [Vercel AI SDK](https://ai-sdk.dev)
|
|
48
|
-
- **Analytics**:
|
|
49
|
-
- [ ] [Posthog](https://posthog.com)
|
|
50
|
-
- **Background Tasks**:
|
|
51
|
-
- [ ] [Inngest](https://www.inngest.com)
|
|
52
|
-
- [ ] [Trigger.dev](https://trigger.dev)
|
|
53
|
-
- **Email**:
|
|
54
|
-
- [ ] [Resend](https://resend.com)
|
|
55
|
-
- [ ] [SendGrid](https://sendgrid.com)
|
|
56
|
-
- **OpenAPI**:
|
|
57
|
-
- [ ] [Scalar](https://scalar.com)
|
|
58
|
-
- **Organization/teams**:
|
|
59
|
-
- [ ] [Better Auth](https://www.better-auth.com/docs/plugins/organization)
|
|
60
|
-
- **Internationalization**:
|
|
61
|
-
- [ ] [i18next](https://www.i18next.com)
|
|
62
|
-
- [ ] [next-intl](https://next-intl.dev)
|
|
63
|
-
- **Payment Processing**:
|
|
64
|
-
- [ ] [Autumn](https://useautumn.com)
|
|
65
|
-
- [ ] [Creem](https://www.creem.io)
|
|
66
|
-
- [ ] [Dodo](https://dodopayments.com)
|
|
67
|
-
- [ ] [Lemon Squeezy](https://www.lemonsqueezy.com)
|
|
68
|
-
- [ ] [Paddle](https://www.paddle.com)
|
|
69
|
-
- [ ] [Polar](https://polar.sh)
|
|
70
|
-
- [ ] [Razorpay](https://razorpay.com)
|
|
71
|
-
- [ ] [Stripe](https://stripe.com)
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## 📂 Project Structure
|
|
76
|
-
|
|
77
|
-
This project is a monorepo organized as follows:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
.
|
|
81
|
-
├── api/
|
|
82
|
-
│ └── hono/ # Backend API server (Hono)
|
|
83
|
-
├── web/
|
|
84
|
-
│ └── next/ # Frontend application (Next.js)
|
|
85
|
-
└── packages/
|
|
86
|
-
├── auth/ # Shared authentication logic (Better Auth)
|
|
87
|
-
├── db/ # Database schema and Drizzle configuration
|
|
88
|
-
├── env/ # Type-safe environment variables
|
|
89
|
-
└── tsconfig/ # Shared TypeScript configuration
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 🔌 Type-Safe API Client
|
|
95
|
-
|
|
96
|
-
This starter utilizes [Hono RPC](https://hono.dev/docs/guides/rpc) to provide end-to-end type safety between the backend and frontend.
|
|
97
|
-
|
|
98
|
-
- **Backend**: Routes defined in `api/hono/src/routers` are exported as `AppType` at `api/hono/src/index.ts`.
|
|
99
|
-
- **Frontend**: The client at `web/next/src/lib/api/client.ts` infers `AppType` request/response types using `hono/client`.
|
|
100
|
-
|
|
101
|
-
### Usage Example
|
|
102
|
-
|
|
103
|
-
```ts
|
|
104
|
-
import { apiClient } from "@/lib/api/client"
|
|
105
|
-
|
|
106
|
-
// Fully typed request and response
|
|
107
|
-
const res = await apiClient.health.$get()
|
|
108
|
-
const data = await res.json()
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## ⚙️ Getting Started
|
|
114
|
-
|
|
115
|
-
### Prerequisites
|
|
116
|
-
|
|
117
|
-
- [Bun](https://bun.sh) (v1.3.0 or later)
|
|
118
|
-
|
|
119
|
-
### Installation
|
|
120
|
-
|
|
121
|
-
1. Clone this template:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
bunx gitpick https://github.com/nrjdalal/zerostarter/tree/main
|
|
125
|
-
cd zerostarter
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
> **Note**: The `main` branch is the latest stable release.
|
|
129
|
-
|
|
130
|
-
2. Install dependencies:
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
bun install
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
> **Note**: If the installation fails, try using `bun install --ignore-scripts`
|
|
137
|
-
|
|
138
|
-
3. Set up environment variables:
|
|
139
|
-
|
|
140
|
-
Create a `.env` file in the root directory with the following variables:
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
# -------------------- Server variables --------------------
|
|
144
|
-
|
|
145
|
-
HONO_APP_URL=http://localhost:4000
|
|
146
|
-
HONO_TRUSTED_ORIGINS=http://localhost:3000
|
|
147
|
-
|
|
148
|
-
# Generate using `openssl rand -base64 32`
|
|
149
|
-
BETTER_AUTH_SECRET=
|
|
150
|
-
|
|
151
|
-
# Generate at `https://github.com/settings/developers`
|
|
152
|
-
GITHUB_CLIENT_ID=
|
|
153
|
-
GITHUB_CLIENT_SECRET=
|
|
154
|
-
|
|
155
|
-
# Generate at `https://console.cloud.google.com/apis/credentials`
|
|
156
|
-
GOOGLE_CLIENT_ID=
|
|
157
|
-
GOOGLE_CLIENT_SECRET=
|
|
158
|
-
|
|
159
|
-
# Generate using `bunx pglaunch -k`
|
|
160
|
-
POSTGRES_URL=
|
|
161
|
-
|
|
162
|
-
# -------------------- Client variables --------------------
|
|
163
|
-
|
|
164
|
-
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
165
|
-
NEXT_PUBLIC_API_URL=http://localhost:4000
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Database Setup
|
|
169
|
-
|
|
170
|
-
1. Ensure your PostgreSQL server is running.
|
|
171
|
-
2. Run the generation:
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
bun run db:generate
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
3. Run the migration:
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
bun run db:migrate
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Authentication Setup
|
|
184
|
-
|
|
185
|
-
ZeroStarter comes with some default authentication plugins using [Better Auth](https://better-auth.com), you can extend as needed.
|
|
186
|
-
|
|
187
|
-
#### Github
|
|
188
|
-
|
|
189
|
-
1. Create a GitHub OAuth App at [GitHub Developer Settings](https://github.com/settings/developers).
|
|
190
|
-
2. Set the **Homepage URL** to `http://localhost:3000`.
|
|
191
|
-
3. Set the **Authorization callback URL** to `http://localhost:3000/api/auth/callback/github`.
|
|
192
|
-
4. Copy the **Client ID** and **Client Secret** into your `.env` file.
|
|
193
|
-
|
|
194
|
-
#### Google
|
|
195
|
-
|
|
196
|
-
1. Create a Google OAuth App in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials.
|
|
197
|
-
2. Configure the OAuth consent screen (External).
|
|
198
|
-
3. Create an **OAuth Client ID** (Application type: Web).
|
|
199
|
-
4. Set the **Authorized JavaScript origins** to `http://localhost:3000`.
|
|
200
|
-
5. Set the **Authorized redirect URI** to `http://localhost:4000/api/auth/callback/google`.
|
|
201
|
-
6. Copy the **Client ID** and **Client Secret** into your `.env` file.
|
|
202
|
-
|
|
203
|
-
### Running the Application
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
bun dev
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Running the Application with Docker Compose
|
|
210
|
-
|
|
211
|
-
```bash
|
|
212
|
-
docker compose up
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Accessing the Application
|
|
216
|
-
|
|
217
|
-
- Frontend: [http://localhost:3000](http://localhost:3000)
|
|
218
|
-
- Backend: [http://localhost:4000](http://localhost:4000)
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## 📜 Scripts
|
|
223
|
-
|
|
224
|
-
### Development
|
|
225
|
-
|
|
226
|
-
- `bun run dev`: Start the development servers.
|
|
227
|
-
|
|
228
|
-
### Maintenance
|
|
229
|
-
|
|
230
|
-
- `bun run clean`: Clean the cache and build artifacts.
|
|
231
|
-
- `bun run lint`: Lint the codebase using Oxlint.
|
|
232
|
-
- `bun run format`: Format the codebase using Prettier.
|
|
233
|
-
- `bun run check-types`: Check the types of the codebase.
|
|
234
|
-
|
|
235
|
-
### Production
|
|
236
|
-
|
|
237
|
-
- `bun run build`: Build the applications.
|
|
238
|
-
- `bun run start`: Start the production servers.
|
|
239
|
-
|
|
240
|
-
### Database
|
|
241
|
-
|
|
242
|
-
- `bun run db:generate`: Generate Drizzle migrations.
|
|
243
|
-
- `bun run db:migrate`: Run Drizzle migrations.
|
|
244
|
-
- `bun run db:studio`: Open Drizzle Studio to view/edit data.
|
|
245
|
-
|
|
246
|
-
## 📖 Deployment
|
|
247
|
-
|
|
248
|
-
- **Frontend**:
|
|
249
|
-
- [Vercel](.github/docs/deployment/vercel.md#vercel)
|
|
250
|
-
- **Backend**:
|
|
251
|
-
- [Vercel](.github/docs/deployment/vercel.md#vercel-1)
|
|
252
|
-
|
|
253
|
-
## 🤝 Contributing
|
|
254
|
-
|
|
255
|
-
Contributions welcome — any help is appreciated!
|
|
256
|
-
|
|
257
|
-
- Fork the repo and create a branch (use descriptive names, e.g. `feat/{name}` or `fix/{name}`).
|
|
258
|
-
- Make your changes, add tests if applicable, and run the checks:
|
|
259
|
-
- `bun run build`
|
|
260
|
-
- `bun run check-types`
|
|
261
|
-
- `bun run format`
|
|
262
|
-
- `bun run lint`
|
|
263
|
-
- Follow the existing code style and commit message conventions (use conventional commits: feat, fix, docs, chore).
|
|
264
|
-
- Open a PR describing the change, motivation, and any migration notes; link related issues.
|
|
265
|
-
- For breaking changes or large features, open an issue first to discuss the approach.
|
|
266
|
-
- By contributing you agree to the MIT license and the project's Code of Conduct.
|
|
267
|
-
|
|
268
|
-
Thank you for helping improve ZeroStarter!
|
|
269
|
-
|
|
270
|
-
## 📄 License
|
|
271
|
-
|
|
272
|
-
This project is licensed under the [MIT](https://github.com/nrjdalal/zerostarter/blob/canary/LICENSE.md) License.
|
|
273
|
-
|
|
274
|
-
<!-- trigger build: 4 -->
|