@@ -13,6 +13,34 @@ const streamPipeline = promisify(pipeline);
1313const MIN_NODE_MAJOR = 18 ;
1414const nodeMajor = Number ( process . versions . node . split ( "." ) [ 0 ] ) ;
1515
16+ function printHelp ( ) {
17+ console . log ( `
18+ create-seamless
19+
20+ Scaffold a local Seamless Auth development environment.
21+
22+ Usage:
23+ npx create-seamless [project-name] [options]
24+
25+ Options:
26+ --auth Include the Seamless Auth server
27+ --api Include the Express API example
28+ --web Include the React web application
29+ --no-git Skip git initialization
30+
31+ --auth-port <n> Auth server port (default: 5312)
32+ --api-port <n> API server port (default: 3000)
33+ --web-port <n> Web server port (default: 5173)
34+
35+ -h, --help Show this help message
36+
37+ If no component flags are provided, all components are included.
38+
39+ Docs:
40+ https://docs.seamlessauth.com
41+ ` ) ;
42+ }
43+
1644if ( nodeMajor < MIN_NODE_MAJOR ) {
1745 console . error ( `
1846❌ Seamless requires Node ${ MIN_NODE_MAJOR } +.
@@ -24,6 +52,11 @@ Upgrade at https://nodejs.org
2452}
2553
2654const args = process . argv . slice ( 2 ) ;
55+
56+ if ( args . includes ( "-h" ) || args . includes ( "--help" ) ) {
57+ printHelp ( ) ;
58+ process . exit ( 0 ) ;
59+ }
2760const projectName = args . find ( ( a ) => ! a . startsWith ( "--" ) ) ?? "seamless-app" ;
2861
2962const hasFlag = ( flag ) => args . includes ( `--${ flag } ` ) ;
@@ -35,7 +68,6 @@ const getFlag = (flag, fallback) => {
3568const includeAuth = hasFlag ( "auth" ) ;
3669const includeWeb = hasFlag ( "web" ) ;
3770const includeApi = hasFlag ( "api" ) ;
38- const installDeps = hasFlag ( "install" ) ;
3971const skipGit = hasFlag ( "no-git" ) ;
4072
4173const authPort = getFlag ( "auth-port" , "5312" ) ;
@@ -71,16 +103,65 @@ It is designed for development environments where you want:
71103
72104\`\`\`text
73105.
74- ├─ auth/ # Seamless Auth open source server
75- ├─ api/ # Backend API server (optional)
76- ├─ web/ # Frontend web application (optional)
106+ ├─ auth/ # Seamless Auth open source server
107+ ├─ api/ # Backend API server (optional)
108+ ├─ web/ # Frontend web application (optional)
109+ ├─ Docker-compose.yml # Docker compose for one command spin up of dev environment
77110└─ README.md
78111\`\`\`
79112
80113---
81114
82115## Running the stack
83116
117+ ### Running with Docker (optional)
118+
119+ This project includes a Docker Compose configuration that allows you to run the
120+ entire Seamless Auth stack locally with a single command.
121+
122+ ### Requirements
123+
124+ * Docker
125+ * Docker Compose
126+
127+ ### Start the stack
128+
129+ From the project root, run:
130+
131+ \`\`\`bash
132+ docker compose up
133+ \`\`\`
134+
135+ This will start the following services in development mode:
136+
137+ * Postgres database
138+ * Seamless Auth server
139+ * API server
140+ * Web UI
141+
142+ All services are configured with hot reload. Changes to the source code will be
143+ picked up automatically.
144+
145+ ### Access the application
146+
147+ Once all services are running, open:
148+
149+ \`\`\`
150+ http://localhost:5001
151+ \`\`\`
152+
153+ This is the main entry point for the web application.
154+
155+ ### Stopping the stack
156+
157+ To stop all services:
158+
159+ \`\`\`bash
160+ docker compose down
161+ \`\`\`
162+
163+ This will shut down all containers while preserving the local database volume.
164+
84165Open separate terminals and run each service independently.
85166
86167### Auth server
@@ -90,7 +171,7 @@ cd auth
90171npm run dev
91172\`\`\`
92173
93- Default port: \`3000 \`
174+ Default port: \`5312 \`
94175
95176---
96177
@@ -101,7 +182,7 @@ cd api
101182npm run dev
102183\`\`\`
103184
104- Default port: \`4000 \`
185+ Default port: \`3000 \`
105186
106187---
107188
@@ -112,7 +193,7 @@ cd web
112193npm run dev
113194\`\`\`
114195
115- Default port: \`5173 \`
196+ Default port: \`5001 \`
116197
117198---
118199
@@ -145,6 +226,64 @@ includes.
145226Review each subproject for its specific license before deploying to production.
146227` ;
147228
229+ const GENERATED_DOCKER_COMPOSE = `
230+ version: "3.9"
231+
232+ services:
233+ db:
234+ image: postgres:16
235+ container_name: seamless-db
236+ ports:
237+ - "5432:5432"
238+ environment:
239+ POSTGRES_USER: seamless
240+ POSTGRES_PASSWORD: seamless
241+ POSTGRES_DB: seamless
242+ volumes:
243+ - pgdata:/var/lib/postgresql/data
244+
245+ auth:
246+ container_name: seamless-auth
247+ build: ./auth
248+ ports:
249+ - "5312:5312"
250+ env_file:
251+ - ./auth/.env
252+ volumes:
253+ - ./auth:/app
254+ depends_on:
255+ - db
256+
257+ api:
258+ container_name: seamless-api
259+ build: ./api
260+ ports:
261+ - "3000:3000"
262+ env_file:
263+ - ./api/.env
264+ volumes:
265+ - ./api:/app
266+ depends_on:
267+ - auth
268+ - db
269+
270+ web:
271+ container_name: seamless-web
272+ build: ./web
273+ ports:
274+ - "5001:5001"
275+ env_file:
276+ - ./web/.env
277+ volumes:
278+ - ./web:/app
279+ depends_on:
280+ - auth
281+ - api
282+
283+ volumes:
284+ pgdata:
285+ ` ;
286+
148287function writeEnv ( dir , values ) {
149288 const env = Object . entries ( values )
150289 . map ( ( [ k , v ] ) => `${ k } =${ v } ` )
@@ -202,8 +341,8 @@ async function downloadRepo(repo, dest) {
202341 VERSION : "1.0.0" ,
203342 APP_NAME : "Seamless Auth Example" ,
204343 APP_ID : "local-dev" ,
205- APP_ORIGIN : " http://localhost:3000" ,
206- ISSUER : " http://localhost:5312" ,
344+ APP_ORIGIN : ` http://localhost:${ apiPort } ` ,
345+ ISSUER : ` http://localhost:${ authPort } ` ,
207346
208347 AUTH_MODE : "server" ,
209348 DEMO : "true" ,
@@ -223,7 +362,7 @@ async function downloadRepo(repo, dest) {
223362 JWKS_ACTIVE_KID : "dev-main" ,
224363
225364 RPID : "localhost" ,
226- ORIGINS : " http://localhost:3000" ,
365+ ORIGINS : ` http://localhost:${ apiPort } ` ,
227366 } ) ;
228367 }
229368
@@ -234,7 +373,7 @@ async function downloadRepo(repo, dest) {
234373 await downloadRepo ( REPOS . api , dir ) ;
235374
236375 writeEnv ( dir , {
237- AUTH_SERVER_URL : `http://localhost${ authPort } ` ,
376+ AUTH_SERVER_URL : `http://localhost: ${ authPort } ` ,
238377 APP_ORIGIN : `http://localhost:${ apiPort } ` ,
239378 COOKIE_SIGNING_KEY : randomBytes ( 32 ) . toString ( "hex" ) ,
240379 API_SERVICE_TOKEN : API_SERVICE_TOKEN ,
@@ -263,14 +402,11 @@ async function downloadRepo(repo, dest) {
263402 execSync ( "git init" , { cwd : root } ) ;
264403 }
265404
266- if ( installDeps ) {
267- for ( const dir of [ "auth" , "api" , "web" ] ) {
268- const full = path . join ( root , dir ) ;
269- if ( fs . existsSync ( full ) ) {
270- console . log ( `Installing deps in ${ dir } ...` ) ;
271- execSync ( "npm install" , { cwd : full , stdio : "inherit" } ) ;
272- }
273- }
405+ if ( AUTH && API && WEB ) {
406+ fs . writeFileSync (
407+ path . join ( root , "Docker-compose.yml" ) ,
408+ GENERATED_DOCKER_COMPOSE ,
409+ ) ;
274410 }
275411
276412 console . log ( `
0 commit comments