create-seamless 0.0.11 → 0.1.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.
Files changed (2) hide show
  1. package/package.json +17 -11
  2. package/index.js +0 -520
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-seamless",
3
- "version": "0.0.11",
3
+ "version": "0.1.0",
4
4
  "description": "The starter script for Seamless Auth",
5
5
  "homepage": "https://github.com/fells-code/create-seamless#readme",
6
6
  "bugs": {
@@ -12,25 +12,31 @@
12
12
  },
13
13
  "license": "AGPL-3.0-only",
14
14
  "author": "Fells Code, LLC",
15
+ "bin": {
16
+ "create-seamless": "dist/index.js"
17
+ },
15
18
  "type": "module",
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsx src/index.ts",
22
+ "clean": "rm -rf dist"
23
+ },
16
24
  "main": "index.js",
17
25
  "files": [
18
- "index.js",
19
26
  "dist",
27
+ "templates",
20
28
  "README.md",
21
29
  "LICENSE"
22
30
  ],
23
- "scripts": {
24
- "test": "echo \"Error: no test specified\" && exit 1"
25
- },
26
- "bin": {
27
- "create-seamlessauth": "index.js"
28
- },
29
31
  "dependencies": {
30
- "adm-zip": "^0.5.16"
32
+ "@clack/prompts": "^1.0.1",
33
+ "adm-zip": "^0.5.16",
34
+ "kleur": "^4.1.5"
31
35
  },
32
36
  "devDependencies": {
33
37
  "@types/adm-zip": "^0.5.7",
34
- "@types/node": "^24.10.1"
38
+ "@types/node": "^24.10.13",
39
+ "tsx": "^4.21.0",
40
+ "typescript": "^5.9.3"
35
41
  }
36
- }
42
+ }
package/index.js DELETED
@@ -1,520 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from "fs";
3
- import path from "path";
4
- import { execSync } from "child_process";
5
- import { pipeline } from "stream";
6
- import { promisify } from "util";
7
- import { createWriteStream } from "fs";
8
- import AdmZip from "adm-zip";
9
- import { randomBytes } from "crypto";
10
- import net from "net";
11
-
12
- const streamPipeline = promisify(pipeline);
13
-
14
- const MIN_NODE_MAJOR = 18;
15
- const nodeMajor = Number(process.versions.node.split(".")[0]);
16
-
17
- function ensureExecutable(filePath) {
18
- if (fs.existsSync(filePath)) {
19
- fs.chmodSync(filePath, 0o755);
20
- }
21
- }
22
-
23
- function isPortAvailable(port) {
24
- return new Promise((resolve) => {
25
- const server = net
26
- .createServer()
27
- .once("error", () => resolve(false))
28
- .once("listening", () => {
29
- server.close();
30
- resolve(true);
31
- })
32
- .listen(port);
33
- });
34
- }
35
-
36
- function printHelp() {
37
- console.log(`
38
- create-seamless
39
-
40
- Scaffold a local Seamless Auth development environment.
41
-
42
- Usage:
43
- npx create-seamless [project-name] [options]
44
-
45
- Options:
46
- --auth Include the Seamless Auth server
47
- --api Include the Express API example
48
- --web Include the React web application
49
- --no-git Skip git initialization
50
-
51
- --auth-port <n> Auth server port (default: 5312)
52
- --api-port <n> API server port (default: 3000)
53
- --web-port <n> Web server port (default: 5001)
54
-
55
- -h, --help Show this help message
56
-
57
- If no component flags are provided, all components are included.
58
-
59
- Docs:
60
- https://docs.seamlessauth.com
61
- `);
62
- }
63
-
64
- if (nodeMajor < MIN_NODE_MAJOR) {
65
- console.error(`
66
- ❌ Seamless requires Node ${MIN_NODE_MAJOR}+.
67
- You are running Node ${process.versions.node}
68
-
69
- Upgrade at https://nodejs.org
70
- `);
71
- process.exit(1);
72
- }
73
-
74
- const args = process.argv.slice(2);
75
-
76
- if (args.includes("-h") || args.includes("--help")) {
77
- printHelp();
78
- process.exit(0);
79
- }
80
- const projectName = args.find((a) => !a.startsWith("--")) ?? "seamless-app";
81
-
82
- const hasFlag = (flag) => args.includes(`--${flag}`);
83
- const getFlag = (flag, fallback) => {
84
- const i = args.indexOf(`--${flag}`);
85
- return i !== -1 ? args[i + 1] : fallback;
86
- };
87
-
88
- const includeAuth = hasFlag("auth");
89
- const includeWeb = hasFlag("web");
90
- const includeApi = hasFlag("api");
91
- const skipGit = hasFlag("no-git");
92
-
93
- const authPort = getFlag("auth-port", "5312");
94
- const apiPort = getFlag("api-port", "3000");
95
- const webPort = getFlag("web-port", "5001");
96
-
97
- const wantsSomething = includeAuth || includeWeb || includeApi;
98
- const AUTH = wantsSomething ? includeAuth : true;
99
- const WEB = wantsSomething ? includeWeb : true;
100
- const API = wantsSomething ? includeApi : true;
101
-
102
- const REPOS = {
103
- auth: "fells-code/seamless-auth-api",
104
- web: "fells-code/seamless-auth-starter-react",
105
- api: "fells-code/seamless-auth-starter-express",
106
- };
107
-
108
- const GENERATED_README = (projectName) => `# ${projectName}
109
-
110
- This project was generated with \`create-seamless\` and provides a fully local,
111
- open source authentication stack built on **Seamless Auth**.
112
-
113
- It is designed for development environments where you want:
114
-
115
- - Passwordless authentication
116
- - No hosted dependencies
117
- - No redirects or third-party auth services
118
- - A production-shaped local setup
119
-
120
- ---
121
-
122
- ## Project layout
123
-
124
- \`\`\`text
125
- .
126
- ├─ auth/ # Seamless Auth open source server
127
- ├─ api/ # Backend API server (optional)
128
- ├─ web/ # Frontend web application (optional)
129
- ├─ Docker-compose.yml # Docker compose for one command spin up of dev environment
130
- └─ README.md
131
- \`\`\`
132
-
133
- ---
134
-
135
- ## Running the stack
136
-
137
- ### Running with Docker (optional)
138
-
139
- This project includes a Docker Compose configuration that allows you to run the
140
- entire Seamless Auth stack locally with a single command.
141
-
142
- ### Requirements
143
-
144
- * Docker
145
- * Docker Compose
146
-
147
- ### Start the stack
148
-
149
- From the project root, run:
150
-
151
- \`\`\`bash
152
- docker compose up
153
- \`\`\`
154
-
155
- This will start the following services in development mode:
156
-
157
- * Postgres database
158
- * Seamless Auth server
159
- * API server
160
- * Web UI
161
-
162
- All services are configured with hot reload. Changes to the source code will be
163
- picked up automatically.
164
-
165
- ### Access the application
166
-
167
- Once all services are running, open:
168
-
169
- \`\`\`
170
- http://localhost:5001
171
- \`\`\`
172
-
173
- This is the main entry point for the web application.
174
-
175
- ### Stopping the stack
176
-
177
- To stop all services:
178
-
179
- \`\`\`bash
180
- docker compose down
181
- \`\`\`
182
-
183
- This will shut down all containers while preserving the local database volume.
184
-
185
- Open separate terminals and run each service independently.
186
-
187
- ### Auth server
188
-
189
- \`\`\`bash
190
- cd auth
191
- npm run dev
192
- \`\`\`
193
-
194
- Default port: \`5312\`
195
-
196
- ---
197
-
198
- ### API server
199
-
200
- \`\`\`bash
201
- cd api
202
- npm run dev
203
- \`\`\`
204
-
205
- Default port: \`3000\`
206
-
207
- ---
208
-
209
- ### Web application
210
-
211
- \`\`\`bash
212
- cd web
213
- npm run dev
214
- \`\`\`
215
-
216
- Default port: \`5001\`
217
-
218
- ---
219
-
220
- ## Documentation
221
-
222
- Full Seamless Auth documentation:
223
-
224
- https://seamlessauth.com/docs
225
-
226
- ---
227
-
228
- ## Included open source projects
229
-
230
- - Seamless Auth Server
231
- https://github.com/fells-code/seamless-auth-server
232
-
233
- - Seamless Auth React Starter
234
- https://github.com/fells-code/seamless-auth-starter-react
235
-
236
- - Seamless Auth API Starter
237
- https://github.com/fells-code/seamless-auth-starter-express
238
-
239
- ---
240
-
241
- ## License
242
-
243
- This generated project inherits the licenses of the open source components it
244
- includes.
245
-
246
- Review each subproject for its specific license before deploying to production.
247
- `;
248
-
249
- const GENERATED_DOCKER_COMPOSE = `
250
- services:
251
- db:
252
- image: postgres:16
253
- container_name: seamless-db
254
- ports:
255
- - "5432:5432"
256
- environment:
257
- POSTGRES_USER: myuser
258
- POSTGRES_PASSWORD: mypassword
259
- POSTGRES_DB: postgres
260
- volumes:
261
- - pgdata:/var/lib/postgresql/data
262
- - ./postgres_init:/docker-entrypoint-initdb.d
263
- healthcheck:
264
- test: ["CMD-SHELL", "pg_isready -U myuser -d postgres"]
265
- interval: 5s
266
- timeout: 5s
267
- retries: 5
268
-
269
- auth:
270
- container_name: seamless-auth
271
- build:
272
- context: ./auth
273
- dockerfile: Dockerfile.dev
274
- ports:
275
- - "${authPort}:${authPort}"
276
- env_file:
277
- - ./auth/.env
278
- environment:
279
- DB_HOST: db
280
- ISSUER: http://auth:${authPort}
281
- volumes:
282
- - ./auth:/app
283
- - /app/node_modules
284
- depends_on:
285
- db:
286
- condition: service_healthy
287
-
288
- api:
289
- container_name: seamless-api
290
- build: ./api
291
- ports:
292
- - "${apiPort}:${apiPort}"
293
- env_file:
294
- - ./api/.env
295
- environment:
296
- AUTH_SERVER_URL: http://auth:${authPort}
297
- DB_HOST: db
298
- volumes:
299
- - ./api:/app
300
- - /app/node_modules
301
- depends_on:
302
- db:
303
- condition: service_healthy
304
-
305
- web:
306
- container_name: seamless-web
307
- build: ./web
308
- ports:
309
- - "${webPort}:${webPort}"
310
- env_file:
311
- - ./web/.env
312
- volumes:
313
- - ./web:/app
314
- - /app/node_modules
315
- depends_on:
316
- - auth
317
- - api
318
-
319
- volumes:
320
- pgdata:
321
- `;
322
-
323
- function writeEnv(dir, values) {
324
- const env = Object.entries(values)
325
- .map(([k, v]) => `${k}=${v}`)
326
- .join("\n");
327
- fs.writeFileSync(path.join(dir, ".env"), env + "\n");
328
- }
329
-
330
- async function downloadRepo(repo, dest) {
331
- const url = `https://codeload.github.com/${repo}/zip/refs/heads/main`;
332
- const res = await fetch(url);
333
- if (!res.ok || !res.body) {
334
- throw new Error(`Failed to download ${repo}`);
335
- }
336
-
337
- const zipPath = path.join(dest, "_repo.zip");
338
- await streamPipeline(res.body, createWriteStream(zipPath));
339
-
340
- const zip = new AdmZip(zipPath);
341
- zip.extractAllTo(dest, true);
342
- fs.unlinkSync(zipPath);
343
-
344
- const inner = fs.readdirSync(dest).find((f) => f.endsWith("-main"));
345
- if (!inner) throw new Error("Unexpected repo structure");
346
-
347
- const innerPath = path.join(dest, inner);
348
- for (const file of fs.readdirSync(innerPath)) {
349
- fs.renameSync(path.join(innerPath, file), path.join(dest, file));
350
- }
351
- fs.rmdirSync(innerPath);
352
- }
353
-
354
- (async () => {
355
- const root = path.join(process.cwd(), projectName);
356
-
357
- if (fs.existsSync(root)) {
358
- console.error("❌ Directory already exists.");
359
- process.exit(1);
360
- }
361
-
362
- fs.mkdirSync(root);
363
-
364
- console.log(`\nCreating Seamless project: ${projectName}\n`);
365
- const API_SERVICE_TOKEN = randomBytes(32).toString("hex");
366
-
367
- let dbHostPort = "5432";
368
-
369
- if (!(await isPortAvailable(5432))) {
370
- dbHostPort = "5433";
371
- console.log(`
372
- ⚠️ Port 5432 is already in use on your machine.
373
- Using 5433 for Docker Postgres instead.
374
- `);
375
- }
376
-
377
- if (AUTH) {
378
- const dir = path.join(root, "auth");
379
- fs.mkdirSync(dir);
380
- console.log("Fetching Seamless Auth OSS...");
381
- await downloadRepo(REPOS.auth, dir);
382
-
383
- writeEnv(dir, {
384
- PORT: authPort,
385
- NODE_ENV: "development",
386
-
387
- VERSION: "1.0.0",
388
- APP_NAME: "Seamless Auth Example",
389
- APP_ID: "local-dev",
390
- APP_ORIGIN: `http://localhost:${apiPort}`,
391
- ISSUER: `http://localhost:${authPort}`,
392
-
393
- AUTH_MODE: "server",
394
- DEMO: "true",
395
-
396
- DEFAULT_ROLES: "user,betaUser",
397
- AVAILABLE_ROLES: "user,admin,betaUser,team",
398
-
399
- DB_LOGGING: "false",
400
- DB_HOST: "localhost",
401
- DB_PORT: dbHostPort,
402
- DB_NAME: "seamless_auth",
403
- DB_USER: "myuser",
404
- DB_PASSWORD: "mypassword",
405
-
406
- ACCESS_TOKEN_TTL: "30m",
407
- REFRESH_TOKEN_TTL: "1h",
408
- RATE_LIMIT: "100",
409
- DELAY_AFTER: "50",
410
-
411
- API_SERVICE_TOKEN: API_SERVICE_TOKEN,
412
-
413
- JWKS_ACTIVE_KID: "dev-main",
414
-
415
- RPID: "localhost",
416
- ORIGINS: `http://localhost:${webPort}`,
417
- });
418
- }
419
-
420
- if (API) {
421
- const dir = path.join(root, "api");
422
- fs.mkdirSync(dir);
423
- console.log("Fetching API starter...");
424
- await downloadRepo(REPOS.api, dir);
425
-
426
- writeEnv(dir, {
427
- AUTH_SERVER_URL: `http://localhost:${authPort}`,
428
- APP_ORIGIN: `http://localhost:${apiPort}`,
429
- UI_ORIGIN: `http://localhost:${webPort}`,
430
- COOKIE_SIGNING_KEY: randomBytes(32).toString("hex"),
431
- API_SERVICE_TOKEN: API_SERVICE_TOKEN,
432
- JWKS_KID: "dev-main",
433
-
434
- DB_HOST: "localhost",
435
- DB_PORT: dbHostPort,
436
- DB_NAME: "seamless_api",
437
- DB_USER: "myuser",
438
- DB_PASSWORD: "mypassword",
439
-
440
- SQL_LOGGING: "false",
441
- });
442
- }
443
-
444
- if (WEB) {
445
- const dir = path.join(root, "web");
446
- fs.mkdirSync(dir);
447
- console.log("Fetching Web starter...");
448
- await downloadRepo(REPOS.web, dir);
449
-
450
- writeEnv(dir, {
451
- VITE_AUTH_SERVER_URL: `http://localhost:${apiPort}/`,
452
- VITE_API_URL: `http://localhost:${apiPort}/`,
453
- PORT: webPort,
454
- });
455
- }
456
-
457
- fs.writeFileSync(path.join(root, "README.md"), GENERATED_README(projectName));
458
-
459
- if (!skipGit) {
460
- execSync("git init", { cwd: root });
461
- }
462
-
463
- if (AUTH && API && WEB) {
464
- const compose = GENERATED_DOCKER_COMPOSE.replace(
465
- '"5432:5432"',
466
- `"${dbHostPort}:5432"`,
467
- );
468
-
469
- fs.writeFileSync(path.join(root, "docker-compose.yml"), compose);
470
- }
471
-
472
- if (AUTH) {
473
- const authScriptPath = path.join(root, "auth", "validateEnvs.sh");
474
- ensureExecutable(authScriptPath);
475
- }
476
-
477
- const pgDir = path.join(root, "postgres_init");
478
- fs.mkdirSync(pgDir);
479
- fs.writeFileSync(
480
- path.join(pgDir, "init.sql"),
481
- `
482
- CREATE DATABASE seamless_auth;
483
- CREATE DATABASE seamless_api;
484
- `,
485
- );
486
-
487
- console.log(`
488
- ╔════════════════════════════════════════╗
489
- ║ S E A M L E S S ║
490
- ╚════════════════════════════════════════╝
491
-
492
- Your local auth stack is ready.
493
-
494
- Start development:
495
-
496
- cd ${projectName}
497
-
498
- # terminal 1
499
- cd auth && npm i && npm run dev
500
-
501
- # terminal 2
502
- cd api && npm i && npm run dev
503
-
504
- # terminal 3
505
- cd web && npm i && npm run dev
506
-
507
- or if using Docker
508
-
509
- docker compose up
510
-
511
- If you already have Postgres running locally,
512
- the generator may map Docker to port 5433 instead.
513
-
514
- Docs: https://docs.seamlessauth.com/docs
515
- Happy hacking. 🚀
516
- `);
517
- })().catch((err) => {
518
- console.error("\n❌ Error:", err.message);
519
- process.exit(1);
520
- });