create-seamless 0.0.11 → 0.1.1

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 (43) hide show
  1. package/README.md +109 -51
  2. package/dist/commands/init.js +65 -0
  3. package/dist/commands/init.js.map +1 -0
  4. package/dist/core/configure.js +25 -0
  5. package/dist/core/configure.js.map +1 -0
  6. package/dist/core/env.js +35 -0
  7. package/dist/core/env.js.map +1 -0
  8. package/dist/core/exec.js +17 -0
  9. package/dist/core/exec.js.map +1 -0
  10. package/dist/core/fetch.js +9 -0
  11. package/dist/core/fetch.js.map +1 -0
  12. package/dist/core/help.js +56 -0
  13. package/dist/core/help.js.map +1 -0
  14. package/dist/core/inspect.js +15 -0
  15. package/dist/core/inspect.js.map +1 -0
  16. package/dist/core/jwks.js +19 -0
  17. package/dist/core/jwks.js.map +1 -0
  18. package/dist/core/output.js +83 -0
  19. package/dist/core/output.js.map +1 -0
  20. package/dist/core/packageManager.js +10 -0
  21. package/dist/core/packageManager.js.map +1 -0
  22. package/dist/core/paths.js +7 -0
  23. package/dist/core/paths.js.map +1 -0
  24. package/dist/core/secrets.js +8 -0
  25. package/dist/core/secrets.js.map +1 -0
  26. package/dist/generators/auth/auth.js +47 -0
  27. package/dist/generators/auth/auth.js.map +1 -0
  28. package/dist/generators/backend/express.js +13 -0
  29. package/dist/generators/backend/express.js.map +1 -0
  30. package/dist/generators/docker/docker.js +231 -0
  31. package/dist/generators/docker/docker.js.map +1 -0
  32. package/dist/generators/frontend/react.js +13 -0
  33. package/dist/generators/frontend/react.js.map +1 -0
  34. package/dist/index.js +17 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/prompts/projectSetup.js +64 -0
  37. package/dist/prompts/projectSetup.js.map +1 -0
  38. package/dist/utils/repoUtils.js +23 -0
  39. package/dist/utils/repoUtils.js.map +1 -0
  40. package/dist/utils/writeEnv.js +9 -0
  41. package/dist/utils/writeEnv.js.map +1 -0
  42. package/package.json +19 -12
  43. package/index.js +0 -520
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/core/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,UAAU,cAAc,CAAC,MAAM,GAAG,EAAE;IACxC,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,47 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { runCommand } from "../../core/exec.js";
4
+ import { writeEnv } from "../../utils/writeEnv.js";
5
+ const AUTH_REPO = "https://github.com/fells-code/seamless-auth-api";
6
+ const AUTH_PORT = 5312;
7
+ export async function generateAuthServer(context, mode) {
8
+ const { root } = context;
9
+ if (mode === "local") {
10
+ await setupLocalAuth(root);
11
+ }
12
+ else {
13
+ await setupDockerAuth(root);
14
+ }
15
+ }
16
+ async function setupLocalAuth(root) {
17
+ const authDir = path.join(root, "auth");
18
+ console.log("Cloning SeamlessAuth server...");
19
+ await runCommand("git", ["clone", AUTH_REPO, "auth"], root);
20
+ console.log("Writing auth environment...");
21
+ writeEnv(authDir, {
22
+ PORT: AUTH_PORT,
23
+ NODE_ENV: "development",
24
+ AUTH_MODE: "server",
25
+ ISSUER: `http://localhost:${AUTH_PORT}`,
26
+ });
27
+ console.log("Auth server ready in /auth");
28
+ }
29
+ async function setupDockerAuth(root) {
30
+ console.log("Creating docker-compose for SeamlessAuth...");
31
+ const dockerCompose = `
32
+ services:
33
+ auth:
34
+ image: ghcr.io/fells-code/seamless-auth-api:v0.1.2
35
+ container_name: seamless-auth
36
+ ports:
37
+ - "5312:5312"
38
+ environment:
39
+ PORT: 5312
40
+ NODE_ENV: development
41
+ AUTH_MODE: server
42
+ ISSUER: http://localhost:5312
43
+ `;
44
+ fs.writeFileSync(path.join(root, "docker-compose.yml"), dockerCompose.trim() + "\n");
45
+ console.log("Docker setup ready.");
46
+ }
47
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/generators/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,SAAS,GAAG,iDAAiD,CAAC;AACpE,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAY,EACZ,IAAiC;IAEjC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAEzB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAE9C,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAE3C,QAAQ,CAAC,OAAO,EAAE;QAChB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,QAAQ;QACnB,MAAM,EAAE,oBAAoB,SAAS,EAAE;KACxC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY;IACzC,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAE3D,MAAM,aAAa,GAAG;;;;;;;;;;;;CAYvB,CAAC;IAEA,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,EACrC,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAC5B,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import path from "path";
2
+ import { cloneRepo, removeGitDir, copyEnvExample, } from "../../utils/repoUtils.js";
3
+ const API_STARTER_REPO = "https://github.com/fells-code/seamless-auth-starter-express.git";
4
+ export async function generateExpressStarter(context) {
5
+ const { root } = context;
6
+ const apiDir = path.join(root, "api");
7
+ console.log("Cloning Seamless Auth Express starter...");
8
+ await cloneRepo(API_STARTER_REPO, apiDir);
9
+ removeGitDir(apiDir);
10
+ copyEnvExample(apiDir);
11
+ console.log("API starter ready.");
12
+ }
13
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../../src/generators/backend/express.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,0BAA0B,CAAC;AAElC,MAAM,gBAAgB,GACpB,iEAAiE,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAyB;IACpE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAEzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEtC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IAExD,MAAM,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAE1C,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,231 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fetchEnvExample } from "../../core/fetch.js";
4
+ import { parseEnv, parseEnvString } from "../../core/env.js";
5
+ import { generateSecret } from "../../core/secrets.js";
6
+ import { generateJWKS } from "../../core/jwks.js";
7
+ export async function generateDockerCompose(root, options) {
8
+ const { compose, shared } = await buildCompose(options, root);
9
+ fs.writeFileSync(path.join(root, "docker-compose.yml"), compose.trim() + "\n");
10
+ console.log("Docker compose created.");
11
+ return shared;
12
+ }
13
+ async function buildCompose(options, root) {
14
+ const { authMode, includeApi, includeWeb } = options;
15
+ const { service: authBlock, shared } = await authService(authMode, root);
16
+ return {
17
+ compose: `
18
+ services:
19
+ db:
20
+ image: postgres:16
21
+ container_name: seamless-db
22
+ ports:
23
+ - "5432:5432"
24
+ environment:
25
+ POSTGRES_USER: myuser
26
+ POSTGRES_PASSWORD: mypassword
27
+ POSTGRES_DB: postgres
28
+ volumes:
29
+ - pgdata:/var/lib/postgresql/data
30
+
31
+ ${authBlock}
32
+
33
+ ${includeApi ? apiService(shared) : ""}
34
+
35
+ ${includeWeb ? webService() : ""}
36
+
37
+ volumes:
38
+ pgdata:
39
+ `,
40
+ shared,
41
+ };
42
+ }
43
+ async function authService(mode, root) {
44
+ if (mode === "local") {
45
+ const shared = await configureAuthLocalEnv(root);
46
+ return {
47
+ service: `
48
+ auth:
49
+ container_name: seamless-auth
50
+ build:
51
+ context: ./auth
52
+ dockerfile: Dockerfile.dev
53
+ ports:
54
+ - "5312:5312"
55
+ env_file:
56
+ - ./auth/.env
57
+ environment:
58
+ DB_HOST: db
59
+ ISSUER: http://auth:5312
60
+ volumes:
61
+ - ./auth:/app
62
+ - /app/node_modules
63
+ depends_on:
64
+ - db
65
+ `,
66
+ shared,
67
+ };
68
+ }
69
+ return await authServiceDocker();
70
+ }
71
+ function apiService(shared) {
72
+ return `
73
+ api:
74
+ container_name: api
75
+ build: ./api
76
+ ports:
77
+ - "3000:3000"
78
+ env_file:
79
+ - ./api/.env
80
+ environment:
81
+ AUTH_SERVER_URL: http://auth:5312
82
+ UI_ORIGIN: http://localhost:5173
83
+ DB_HOST: db
84
+ API_SERVICE_TOKEN: ${shared.apiToken}
85
+ JWKS_KID: ${shared.kid}
86
+ volumes:
87
+ - ./api:/app
88
+ - /app/node_modules
89
+ depends_on:
90
+ - db
91
+ - auth
92
+ `;
93
+ }
94
+ function webService() {
95
+ return `
96
+ web:
97
+ container_name: web
98
+ build: ./web
99
+ ports:
100
+ - "5173:5173"
101
+ env_file:
102
+ - ./web/.env
103
+ environment:
104
+ VITE_API_URL: http://localhost:3000
105
+ VITE_AUTH_SERVER_URL: http://localhost:3000/
106
+ volumes:
107
+ - ./web:/app
108
+ - /app/node_modules
109
+ depends_on:
110
+ - auth
111
+ - api
112
+ `;
113
+ }
114
+ async function authServiceDocker() {
115
+ const raw = await fetchEnvExample();
116
+ const parsed = parseEnvString(raw);
117
+ const { env, shared } = buildAuthEnv(parsed, "docker");
118
+ const envBlock = envToDockerBlock(env);
119
+ return {
120
+ service: `
121
+ auth:
122
+ image: ghcr.io/fells-code/seamless-auth-api:v0.1.5
123
+ container_name: seamless-auth
124
+ ports:
125
+ - "5312:5312"
126
+ environment:
127
+ ${envBlock}
128
+ depends_on:
129
+ - db
130
+ `,
131
+ shared,
132
+ };
133
+ }
134
+ function buildAuthEnv(env, mode) {
135
+ const apiToken = generateSecret(32);
136
+ env.PORT = "5312";
137
+ env.NODE_ENV = mode === "docker" ? "production" : "development";
138
+ env.AUTH_MODE = "server";
139
+ env.ISSUER = "http://auth:5312";
140
+ env.DB_HOST = mode === "docker" ? "db" : "localhost";
141
+ env.DB_PORT = "5432";
142
+ env.API_SERVICE_TOKEN = apiToken;
143
+ let kid = "main";
144
+ env.JWKS_ACTIVE_KID = kid;
145
+ if (mode === "docker") {
146
+ const jwks = buildJWKSConfig();
147
+ kid = jwks.kid;
148
+ env.SEAMLESS_JWKS_ACTIVE_KID = jwks.kid;
149
+ env.JWKS_ACTIVE_KID = jwks.kid;
150
+ env[`SEAMLESS_JWKS_KEY_${jwks.kid}_PRIVATE`] = jwks.privateKey;
151
+ env.JWKS_PUBLIC_KEYS = jwks.publicJwksJson;
152
+ }
153
+ env.APP_ORIGIN = "http://localhost:3000";
154
+ env.ORIGINS = "http://localhost:5173";
155
+ return {
156
+ env,
157
+ shared: {
158
+ apiToken,
159
+ kid,
160
+ },
161
+ };
162
+ }
163
+ export function envToDockerBlock(env) {
164
+ return Object.entries(env)
165
+ .map(([k, v]) => {
166
+ if (v.includes("\n")) {
167
+ return ` ${k}: |\n${indentMultiline(v, 8)}`;
168
+ }
169
+ return ` ${k}: ${v}`;
170
+ })
171
+ .join("\n");
172
+ }
173
+ function indentMultiline(value, spaces) {
174
+ const indent = " ".repeat(spaces);
175
+ return value
176
+ .split("\n")
177
+ .map((line) => `${indent}${line}`)
178
+ .join("\n");
179
+ }
180
+ export function buildJWKSConfig() {
181
+ const kid = "main";
182
+ const { publicKey, privateKey } = generateJWKS();
183
+ return {
184
+ kid,
185
+ privateKey,
186
+ publicKey,
187
+ publicJwksJson: JSON.stringify({
188
+ keys: [
189
+ {
190
+ kid,
191
+ pem: publicKey,
192
+ },
193
+ ],
194
+ }, null, 2),
195
+ };
196
+ }
197
+ export async function configureAuthLocalEnv(root) {
198
+ const authDir = path.join(root, "auth");
199
+ const envExamplePath = path.join(authDir, ".env.example");
200
+ const envPath = path.join(authDir, ".env");
201
+ if (!fs.existsSync(envExamplePath)) {
202
+ throw new Error(".env.example not found in auth directory");
203
+ }
204
+ const raw = fs.readFileSync(envExamplePath, "utf-8");
205
+ const parsed = parseEnvString(raw);
206
+ const { env, shared } = buildAuthEnv(parsed, "local");
207
+ writeEnvFile(envPath, env);
208
+ return shared;
209
+ }
210
+ function writeEnvFile(filePath, env) {
211
+ const content = Object.entries(env)
212
+ .map(([k, v]) => {
213
+ if (v.includes("\n")) {
214
+ return `${k}="${escapeMultiline(v)}"`;
215
+ }
216
+ return `${k}=${v}`;
217
+ })
218
+ .join("\n");
219
+ fs.writeFileSync(filePath, content + "\n");
220
+ }
221
+ function escapeMultiline(value) {
222
+ return value.replace(/\n/g, "\\n");
223
+ }
224
+ export function extractSharedFromExistingEnv(root) {
225
+ const env = parseEnv(path.join(root, "auth", ".env"));
226
+ return {
227
+ apiToken: env.API_SERVICE_TOKEN,
228
+ kid: env.JWKS_ACTIVE_KID || "main",
229
+ };
230
+ }
231
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../../../src/generators/docker/docker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import path from "path";
2
+ import { cloneRepo, removeGitDir, copyEnvExample, } from "../../utils/repoUtils.js";
3
+ const WEB_STARTER_REPO = "https://github.com/fells-code/seamless-auth-starter-react.git";
4
+ export async function generateReactStarter(context) {
5
+ const { root } = context;
6
+ const webDir = path.join(root, "web");
7
+ console.log("Cloning Seamless Auth React starter...");
8
+ await cloneRepo(WEB_STARTER_REPO, webDir);
9
+ removeGitDir(webDir);
10
+ copyEnvExample(webDir);
11
+ console.log("Web starter ready.");
12
+ }
13
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../../../src/generators/frontend/react.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,0BAA0B,CAAC;AAElC,MAAM,gBAAgB,GACpB,+DAA+D,CAAC;AAElE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAyB;IAClE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEtC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAEtD,MAAM,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAE1C,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AACpC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { runCLI } from "./commands/init.js";
3
+ import { printHelp } from "./core/help.js";
4
+ const args = process.argv.slice(2);
5
+ const firstArg = args[0];
6
+ async function main() {
7
+ if (firstArg === "-h" || firstArg === "--help") {
8
+ printHelp();
9
+ return;
10
+ }
11
+ await runCLI(firstArg);
12
+ }
13
+ main().catch((err) => {
14
+ console.error("Error:", err.message);
15
+ process.exit(1);
16
+ });
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAEzB,KAAK,UAAU,IAAI;IACjB,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC/C,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { confirm, select } from "@clack/prompts";
2
+ export async function runProjectSetupPrompts() {
3
+ const web = await confirm({
4
+ message: "Do you want to create a web application?",
5
+ });
6
+ let webFramework = null;
7
+ if (web) {
8
+ const result = await select({
9
+ message: "Which framework?",
10
+ options: [
11
+ { value: "react", label: "React (Vite)" },
12
+ { value: "next", label: "Next.js (coming soon)", disabled: true },
13
+ { value: "vue", label: "Vue (coming soon)", disabled: true },
14
+ { value: "angular", label: "Angular (coming soon)", disabled: true },
15
+ ],
16
+ });
17
+ webFramework = result;
18
+ }
19
+ const api = await confirm({
20
+ message: "Do you want to create an API server?",
21
+ });
22
+ let apiFramework = null;
23
+ if (api) {
24
+ const result = await select({
25
+ message: "Which backend?",
26
+ options: [
27
+ { value: "express", label: "Express" },
28
+ { value: "next", label: "Next.js (coming soon)", disabled: true },
29
+ { value: "fastify", label: "Fastify (coming soon)", disabled: true },
30
+ { value: "fast-api", label: "FastAPI (coming soon)", disabled: true },
31
+ ],
32
+ });
33
+ apiFramework = result;
34
+ }
35
+ const authMode = (await select({
36
+ message: "How would you like to run SeamlessAuth?",
37
+ options: [
38
+ {
39
+ value: "local",
40
+ label: "Local development server (npm run dev yourself)",
41
+ },
42
+ {
43
+ value: "docker",
44
+ label: "Docker container (recommended - just run docker compose up)",
45
+ },
46
+ ],
47
+ }));
48
+ let useDocker = await confirm({
49
+ message: "Do you want to run your stack with Docker?",
50
+ });
51
+ if (authMode === "docker" && !useDocker) {
52
+ console.log("\nAuth server requires Docker — enabling Docker mode automatically.\n");
53
+ useDocker = true;
54
+ }
55
+ return {
56
+ web,
57
+ webFramework,
58
+ api,
59
+ apiFramework,
60
+ authMode,
61
+ useDocker,
62
+ };
63
+ }
64
+ //# sourceMappingURL=projectSetup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectSetup.js","sourceRoot":"","sources":["../../src/prompts/projectSetup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAQ,MAAM,gBAAgB,CAAC;AAMvD,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;QACxB,OAAO,EAAE,0CAA0C;KACpD,CAAC,CAAC;IAEH,IAAI,YAAY,GAAiB,IAAI,CAAC;IAEtC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;YAC1B,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE;gBACzC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACjE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC5D,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,IAAI,EAAE;aACrE;SACF,CAAC,CAAC;QAEH,YAAY,GAAG,MAAsB,CAAC;IACxC,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;QACxB,OAAO,EAAE,sCAAsC;KAChD,CAAC,CAAC;IAEH,IAAI,YAAY,GAAiB,IAAI,CAAC;IAEtC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;YAC1B,OAAO,EAAE,gBAAgB;YACzB,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;gBACtC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACjE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACpE,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,IAAI,EAAE;aACtE;SACF,CAAC,CAAC;QAEH,YAAY,GAAG,MAAsB,CAAC;IACxC,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC;QAC7B,OAAO,EAAE,yCAAyC;QAClD,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,iDAAiD;aACzD;YACD;gBACE,KAAK,EAAE,QAAQ;gBACf,KAAK,EAAE,6DAA6D;aACrE;SACF;KACF,CAAC,CAAa,CAAC;IAEhB,IAAI,SAAS,GAAG,MAAM,OAAO,CAAC;QAC5B,OAAO,EAAE,4CAA4C;KACtD,CAAC,CAAC;IAEH,IAAI,QAAQ,KAAK,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CACT,uEAAuE,CACxE,CAAC;QACF,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,GAAG;QACH,YAAY;QACZ,GAAG;QACH,YAAY;QACZ,QAAQ;QACR,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { runCommand } from "../core/exec.js";
4
+ export async function cloneRepo(repoUrl, dest) {
5
+ const parentDir = path.dirname(dest);
6
+ const folderName = path.basename(dest);
7
+ fs.mkdirSync(parentDir, { recursive: true });
8
+ await runCommand("git", ["clone", "--depth", "1", repoUrl, folderName], parentDir);
9
+ }
10
+ export function removeGitDir(projectRoot) {
11
+ const gitDir = path.join(projectRoot, ".git");
12
+ if (fs.existsSync(gitDir)) {
13
+ fs.rmSync(gitDir, { recursive: true, force: true });
14
+ }
15
+ }
16
+ export function copyEnvExample(projectRoot) {
17
+ const envExample = path.join(projectRoot, ".env.example");
18
+ const env = path.join(projectRoot, ".env");
19
+ if (fs.existsSync(envExample) && !fs.existsSync(env)) {
20
+ fs.copyFileSync(envExample, env);
21
+ }
22
+ }
23
+ //# sourceMappingURL=repoUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoUtils.js","sourceRoot":"","sources":["../../src/utils/repoUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe,EAAE,IAAY;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEvC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,MAAM,UAAU,CACd,KAAK,EACL,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,EAC9C,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAE3C,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACnC,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ export function writeEnv(dir, values) {
4
+ const env = Object.entries(values)
5
+ .map(([k, v]) => `${k}=${v}`)
6
+ .join("\n");
7
+ fs.writeFileSync(path.join(dir, ".env"), env + "\n");
8
+ }
9
+ //# sourceMappingURL=writeEnv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeEnv.js","sourceRoot":"","sources":["../../src/utils/writeEnv.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,MAA2B;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;SAC5B,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;AACvD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-seamless",
3
- "version": "0.0.11",
3
+ "version": "0.1.1",
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,32 @@
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",
16
- "main": "index.js",
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsx src/index.ts",
22
+ "clean": "rm -rf dist",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "main": "dist/index.js",
17
26
  "files": [
18
- "index.js",
19
27
  "dist",
28
+ "templates",
20
29
  "README.md",
21
30
  "LICENSE"
22
31
  ],
23
- "scripts": {
24
- "test": "echo \"Error: no test specified\" && exit 1"
25
- },
26
- "bin": {
27
- "create-seamlessauth": "index.js"
28
- },
29
32
  "dependencies": {
30
- "adm-zip": "^0.5.16"
33
+ "@clack/prompts": "^1.0.1",
34
+ "adm-zip": "^0.5.16",
35
+ "kleur": "^4.1.5"
31
36
  },
32
37
  "devDependencies": {
33
38
  "@types/adm-zip": "^0.5.7",
34
- "@types/node": "^24.10.1"
39
+ "@types/node": "^24.10.13",
40
+ "tsx": "^4.21.0",
41
+ "typescript": "^5.9.3"
35
42
  }
36
- }
43
+ }