seamless-cli 0.2.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 (100) hide show
  1. package/LICENSE +79 -0
  2. package/LICENSE.md +26 -0
  3. package/README.md +238 -0
  4. package/dist/commands/bootstrapAdmin.js +96 -0
  5. package/dist/commands/bootstrapAdmin.js.map +1 -0
  6. package/dist/commands/check.js +92 -0
  7. package/dist/commands/check.js.map +1 -0
  8. package/dist/commands/contribute.js +121 -0
  9. package/dist/commands/contribute.js.map +1 -0
  10. package/dist/commands/deploy.js +190 -0
  11. package/dist/commands/deploy.js.map +1 -0
  12. package/dist/commands/destroy.js +122 -0
  13. package/dist/commands/destroy.js.map +1 -0
  14. package/dist/commands/help.js +103 -0
  15. package/dist/commands/help.js.map +1 -0
  16. package/dist/commands/init.js +73 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/contributor/catalog.js +129 -0
  19. package/dist/contributor/catalog.js.map +1 -0
  20. package/dist/contributor/workspace.js +551 -0
  21. package/dist/contributor/workspace.js.map +1 -0
  22. package/dist/core/acm.js +24 -0
  23. package/dist/core/acm.js.map +1 -0
  24. package/dist/core/aws.js +374 -0
  25. package/dist/core/aws.js.map +1 -0
  26. package/dist/core/bootstrapSecret.js +31 -0
  27. package/dist/core/bootstrapSecret.js.map +1 -0
  28. package/dist/core/buildPush.js +91 -0
  29. package/dist/core/buildPush.js.map +1 -0
  30. package/dist/core/configure.js +25 -0
  31. package/dist/core/configure.js.map +1 -0
  32. package/dist/core/deployConfig.js +66 -0
  33. package/dist/core/deployConfig.js.map +1 -0
  34. package/dist/core/deployManifest.js +163 -0
  35. package/dist/core/deployManifest.js.map +1 -0
  36. package/dist/core/deploySecrets.js +31 -0
  37. package/dist/core/deploySecrets.js.map +1 -0
  38. package/dist/core/destroy.js +38 -0
  39. package/dist/core/destroy.js.map +1 -0
  40. package/dist/core/env.js +35 -0
  41. package/dist/core/env.js.map +1 -0
  42. package/dist/core/envDiscovery.js +153 -0
  43. package/dist/core/envDiscovery.js.map +1 -0
  44. package/dist/core/envRegistry.js +76 -0
  45. package/dist/core/envRegistry.js.map +1 -0
  46. package/dist/core/exec.js +17 -0
  47. package/dist/core/exec.js.map +1 -0
  48. package/dist/core/fetch.js +9 -0
  49. package/dist/core/fetch.js.map +1 -0
  50. package/dist/core/health.js +11 -0
  51. package/dist/core/health.js.map +1 -0
  52. package/dist/core/help.js +75 -0
  53. package/dist/core/help.js.map +1 -0
  54. package/dist/core/inspect.js +15 -0
  55. package/dist/core/inspect.js.map +1 -0
  56. package/dist/core/jwks.js +19 -0
  57. package/dist/core/jwks.js.map +1 -0
  58. package/dist/core/output.js +94 -0
  59. package/dist/core/output.js.map +1 -0
  60. package/dist/core/packageManager.js +10 -0
  61. package/dist/core/packageManager.js.map +1 -0
  62. package/dist/core/paths.js +7 -0
  63. package/dist/core/paths.js.map +1 -0
  64. package/dist/core/preReqs.js +14 -0
  65. package/dist/core/preReqs.js.map +1 -0
  66. package/dist/core/secrets.js +8 -0
  67. package/dist/core/secrets.js.map +1 -0
  68. package/dist/core/terraform.js +34 -0
  69. package/dist/core/terraform.js.map +1 -0
  70. package/dist/core/tfVars.js +69 -0
  71. package/dist/core/tfVars.js.map +1 -0
  72. package/dist/generators/admin/admin.js +2 -0
  73. package/dist/generators/admin/admin.js.map +1 -0
  74. package/dist/generators/auth/auth.js +47 -0
  75. package/dist/generators/auth/auth.js.map +1 -0
  76. package/dist/generators/backend/express.js +13 -0
  77. package/dist/generators/backend/express.js.map +1 -0
  78. package/dist/generators/config/config.js +43 -0
  79. package/dist/generators/config/config.js.map +1 -0
  80. package/dist/generators/deploy/aws/dev/files.js +36 -0
  81. package/dist/generators/deploy/aws/dev/files.js.map +1 -0
  82. package/dist/generators/deploy/aws/dev/template.js +1240 -0
  83. package/dist/generators/deploy/aws/dev/template.js.map +1 -0
  84. package/dist/generators/docker/docker.js +263 -0
  85. package/dist/generators/docker/docker.js.map +1 -0
  86. package/dist/generators/frontend/react.js +13 -0
  87. package/dist/generators/frontend/react.js.map +1 -0
  88. package/dist/index.js +43 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/prompts/contributeSetup.js +39 -0
  91. package/dist/prompts/contributeSetup.js.map +1 -0
  92. package/dist/prompts/deploySetup.js +244 -0
  93. package/dist/prompts/deploySetup.js.map +1 -0
  94. package/dist/prompts/projectSetup.js +73 -0
  95. package/dist/prompts/projectSetup.js.map +1 -0
  96. package/dist/utils/repoUtils.js +23 -0
  97. package/dist/utils/repoUtils.js.map +1 -0
  98. package/dist/utils/writeEnv.js +9 -0
  99. package/dist/utils/writeEnv.js.map +1 -0
  100. package/package.json +43 -0
@@ -0,0 +1,190 @@
1
+ import * as p from "@clack/prompts";
2
+ import pc from "picocolors";
3
+ import path from "node:path";
4
+ import { cwd } from "node:process";
5
+ import { discoverAndResolveCustomEnv } from "../core/envDiscovery.js";
6
+ import { mergeDeployConfig, readSeamlessConfig, validateRequiredServices, writeSeamlessConfig, } from "../core/deployConfig.js";
7
+ import { buildDeployManifest, readExistingDeployManifest, updateDeployManifestCertificateArn, updateDeployManifestEnv, writeDeployManifest, } from "../core/deployManifest.js";
8
+ import { getAwsIdentity } from "../core/aws.js";
9
+ import { buildAndPushImages } from "../core/buildPush.js";
10
+ import { runPostDeployHealthChecks } from "../core/health.js";
11
+ import { ensureRequiredCommands } from "../core/preReqs.js";
12
+ import { terraformApply, terraformInit, terraformOutput, } from "../core/terraform.js";
13
+ import { buildAwsDevTfvars, updateAwsDevTfvarsCertificateArn, updateAwsDevTfvarsImages, writeAwsDevTfvars, } from "../core/tfVars.js";
14
+ import { generateAwsDevInfra } from "../generators/deploy/aws/dev/files.js";
15
+ import { promptDeploySetup } from "../prompts/deploySetup.js";
16
+ import { ensureAcmCertificate } from "../core/acm.js";
17
+ export async function deploy(options = {}) {
18
+ const projectDir = options.cwd ? path.resolve(options.cwd) : cwd();
19
+ const setup = p.spinner();
20
+ setup.start("Loading project configuration");
21
+ let config;
22
+ try {
23
+ config = readSeamlessConfig(projectDir);
24
+ validateRequiredServices(config);
25
+ setup.stop("Project configuration loaded");
26
+ }
27
+ catch (error) {
28
+ setup.stop("Failed to load project configuration");
29
+ const message = error instanceof Error ? error.message : "Unknown error";
30
+ p.log.error(message);
31
+ process.exit(1);
32
+ }
33
+ const answers = await promptDeploySetup(config);
34
+ if (answers.tier !== "dev") {
35
+ p.log.warn(`Tier "${answers.tier}" is not implemented yet. Continuing with dev-oriented flow.`);
36
+ }
37
+ const prereqs = p.spinner();
38
+ prereqs.start("Validating local deployment prerequisites");
39
+ try {
40
+ await ensureRequiredCommands();
41
+ prereqs.stop("Prerequisites validated");
42
+ }
43
+ catch (error) {
44
+ prereqs.stop("Prerequisite validation failed");
45
+ const message = error instanceof Error ? error.message : "Unknown error";
46
+ p.log.error(message);
47
+ process.exit(1);
48
+ }
49
+ const persist = p.spinner();
50
+ persist.start("Saving deployment settings");
51
+ try {
52
+ const updated = mergeDeployConfig(config, answers);
53
+ writeSeamlessConfig(projectDir, updated);
54
+ persist.stop("Deployment settings saved");
55
+ }
56
+ catch (error) {
57
+ persist.stop("Failed to save deployment settings");
58
+ const message = error instanceof Error ? error.message : "Unknown error";
59
+ p.log.error(message);
60
+ process.exit(1);
61
+ }
62
+ const existingManifest = readExistingDeployManifest(projectDir);
63
+ let manifest = buildDeployManifest(config, answers, existingManifest);
64
+ const generate = p.spinner();
65
+ generate.start("Generating deployment manifest and Terraform files");
66
+ try {
67
+ writeDeployManifest(projectDir, manifest);
68
+ generateAwsDevInfra(projectDir, manifest);
69
+ writeAwsDevTfvars(projectDir, buildAwsDevTfvars(manifest));
70
+ generate.stop("Deployment files generated");
71
+ }
72
+ catch (error) {
73
+ generate.stop("Failed to generate deployment files");
74
+ const message = error instanceof Error ? error.message : "Unknown error";
75
+ p.log.error(message);
76
+ process.exit(1);
77
+ }
78
+ const envs = p.spinner();
79
+ envs.start("Discovering custom application environment variables");
80
+ try {
81
+ const resolvedEnv = await discoverAndResolveCustomEnv(projectDir, manifest);
82
+ manifest = updateDeployManifestEnv(projectDir, resolvedEnv);
83
+ generateAwsDevInfra(projectDir, manifest);
84
+ writeAwsDevTfvars(projectDir, buildAwsDevTfvars(manifest));
85
+ envs.stop("Custom environment variables resolved");
86
+ }
87
+ catch (error) {
88
+ envs.stop("Failed to resolve custom environment variables");
89
+ const message = error instanceof Error ? error.message : "Unknown error";
90
+ p.log.error(message);
91
+ process.exit(1);
92
+ }
93
+ const account = p.spinner();
94
+ account.start("Resolving AWS account identity");
95
+ let identity;
96
+ try {
97
+ identity = await getAwsIdentity(answers.awsProfile, answers.region);
98
+ account.stop(`Using AWS account ${identity.accountId}`);
99
+ }
100
+ catch (error) {
101
+ account.stop("Failed to resolve AWS account identity");
102
+ const message = error instanceof Error ? error.message : "Unknown error";
103
+ p.log.error(message);
104
+ process.exit(1);
105
+ }
106
+ const certificate = p.spinner();
107
+ certificate.start("Requesting and validating ACM certificate");
108
+ try {
109
+ const certificateArn = await ensureAcmCertificate(manifest);
110
+ manifest = updateDeployManifestCertificateArn(projectDir, certificateArn);
111
+ updateAwsDevTfvarsCertificateArn(projectDir, certificateArn);
112
+ certificate.stop("ACM certificate issued");
113
+ }
114
+ catch (error) {
115
+ certificate.stop("ACM certificate setup failed");
116
+ const message = error instanceof Error ? error.message : "Unknown error";
117
+ p.log.error(message);
118
+ process.exit(1);
119
+ }
120
+ const images = p.spinner();
121
+ images.start("Ensuring ECR repositories and pushing container images");
122
+ try {
123
+ const imageUris = await buildAndPushImages(projectDir, manifest, identity.accountId);
124
+ updateAwsDevTfvarsImages(projectDir, imageUris);
125
+ images.stop("Images built and pushed");
126
+ }
127
+ catch (error) {
128
+ images.stop("Image build or push failed");
129
+ const message = error instanceof Error ? error.message : "Unknown error";
130
+ p.log.error(message);
131
+ process.exit(1);
132
+ }
133
+ const infra = p.spinner();
134
+ infra.start("Applying Terraform infrastructure");
135
+ try {
136
+ await terraformInit(projectDir);
137
+ //await terraformPlan(projectDir);
138
+ await terraformApply(projectDir);
139
+ infra.stop("Infrastructure applied");
140
+ }
141
+ catch (error) {
142
+ infra.stop("Terraform apply failed");
143
+ const message = error instanceof Error ? error.message : "Unknown error";
144
+ p.log.error(message);
145
+ process.exit(1);
146
+ }
147
+ const output = p.spinner();
148
+ output.start("Reading deployment outputs");
149
+ let webUrl = "";
150
+ let apiUrl = "";
151
+ let authUrl = "";
152
+ let adminUrl = "";
153
+ try {
154
+ webUrl = await terraformOutput(projectDir, "web_url");
155
+ apiUrl = await terraformOutput(projectDir, "api_url");
156
+ authUrl = await terraformOutput(projectDir, "auth_url");
157
+ adminUrl = await terraformOutput(projectDir, "admin_url");
158
+ output.stop("Deployment outputs ready");
159
+ }
160
+ catch (error) {
161
+ output.stop("Failed to read Terraform outputs");
162
+ const message = error instanceof Error ? error.message : "Unknown error";
163
+ p.log.error(message);
164
+ process.exit(1);
165
+ }
166
+ const health = p.spinner();
167
+ health.start("Running post-deploy health checks");
168
+ try {
169
+ await runPostDeployHealthChecks({
170
+ web: webUrl,
171
+ api: apiUrl,
172
+ auth: authUrl,
173
+ admin: adminUrl,
174
+ });
175
+ health.stop("Health checks passed");
176
+ }
177
+ catch (error) {
178
+ health.stop("Health checks failed");
179
+ const message = error instanceof Error ? error.message : "Unknown error";
180
+ p.log.warn(message);
181
+ }
182
+ p.note([
183
+ `Web: ${webUrl}`,
184
+ `API: ${apiUrl}`,
185
+ `Auth: ${authUrl}`,
186
+ `Admin: ${adminUrl}`,
187
+ ].join("\n"), "Deployment complete");
188
+ p.outro(pc.green("Seamless deploy finished."));
189
+ }
190
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import * as p from "@clack/prompts";
2
+ import pc from "picocolors";
3
+ import path from "node:path";
4
+ import { cwd } from "node:process";
5
+ import { readSeamlessConfig } from "../core/deployConfig.js";
6
+ import { readDeployManifest } from "../core/deployManifest.js";
7
+ import { removeGeneratedInfraFiles, destroyEcrResources, } from "../core/destroy.js";
8
+ import { ensureRequiredCommands } from "../core/preReqs.js";
9
+ import { terraformDestroy, terraformOutput } from "../core/terraform.js";
10
+ import { emptyVersionedS3Bucket } from "../core/aws.js";
11
+ export async function destroy(options = {}) {
12
+ const projectDir = options.cwd ? path.resolve(options.cwd) : cwd();
13
+ const load = p.spinner();
14
+ load.start("Loading deployment state");
15
+ let projectName = "unknown-project";
16
+ let manifest;
17
+ let backupBucketName = "";
18
+ try {
19
+ backupBucketName = await terraformOutput(projectDir, "backup_bucket_name");
20
+ }
21
+ catch { }
22
+ try {
23
+ const config = readSeamlessConfig(projectDir);
24
+ projectName = config.projectName;
25
+ manifest = readDeployManifest(projectDir);
26
+ load.stop("Deployment state loaded");
27
+ }
28
+ catch (error) {
29
+ load.stop("Failed to load deployment state");
30
+ const message = error instanceof Error ? error.message : "Unknown error";
31
+ p.log.error(message);
32
+ process.exit(1);
33
+ }
34
+ p.note([
35
+ `Project: ${projectName}`,
36
+ `Region: ${manifest.region}`,
37
+ `Web: https://${manifest.domain.webHost}`,
38
+ `API: https://${manifest.domain.apiHost}`,
39
+ `Auth: https://${manifest.domain.authHost}`,
40
+ `Admin: https://${manifest.domain.adminHost}`,
41
+ `Terraform: infra/aws/dev`,
42
+ `ECR cleanup: enabled`,
43
+ ].join("\n"), "Destroy summary");
44
+ const confirmed = await p.confirm({
45
+ message: "This will destroy deployed infrastructure and delete managed ECR repositories. Continue?",
46
+ initialValue: false,
47
+ });
48
+ if (backupBucketName) {
49
+ const deleteBackups = await p.confirm({
50
+ message: `Permanently delete all objects and versions in backup bucket "${backupBucketName}"?`,
51
+ initialValue: false,
52
+ });
53
+ if (p.isCancel(deleteBackups) || !deleteBackups) {
54
+ p.cancel("Destroy cancelled because backup bucket deletion was not confirmed");
55
+ process.exit(0);
56
+ }
57
+ }
58
+ if (p.isCancel(confirmed) || !confirmed) {
59
+ p.cancel("Destroy cancelled");
60
+ process.exit(0);
61
+ }
62
+ const prereqs = p.spinner();
63
+ prereqs.start("Validating destroy prerequisites");
64
+ try {
65
+ await ensureRequiredCommands();
66
+ prereqs.stop("Destroy prerequisites validated");
67
+ }
68
+ catch (error) {
69
+ prereqs.stop("Destroy prerequisite validation failed");
70
+ const message = error instanceof Error ? error.message : "Unknown error";
71
+ p.log.error(message);
72
+ process.exit(1);
73
+ }
74
+ if (backupBucketName) {
75
+ const bucket = p.spinner();
76
+ bucket.start(`Emptying backup bucket ${backupBucketName}`);
77
+ try {
78
+ await emptyVersionedS3Bucket(manifest.awsProfile, manifest.region, backupBucketName);
79
+ bucket.stop("Backup bucket emptied");
80
+ }
81
+ catch (error) {
82
+ bucket.stop("Failed to empty backup bucket");
83
+ const message = error instanceof Error ? error.message : "Unknown error";
84
+ p.log.warn(message);
85
+ }
86
+ }
87
+ const tf = p.spinner();
88
+ tf.start("Destroying Terraform-managed infrastructure");
89
+ try {
90
+ await terraformDestroy(projectDir);
91
+ tf.stop("Terraform-managed infrastructure destroyed");
92
+ }
93
+ catch (error) {
94
+ tf.stop("Terraform destroy failed");
95
+ const message = error instanceof Error ? error.message : "Unknown error";
96
+ p.log.warn(message);
97
+ }
98
+ const ecr = p.spinner();
99
+ ecr.start("Deleting managed ECR repositories");
100
+ try {
101
+ await destroyEcrResources(manifest);
102
+ ecr.stop("Managed ECR repositories deleted");
103
+ }
104
+ catch (error) {
105
+ ecr.stop("ECR cleanup failed");
106
+ const message = error instanceof Error ? error.message : "Unknown error";
107
+ p.log.warn(message);
108
+ }
109
+ const local = p.spinner();
110
+ local.start("Removing generated local deploy artifacts");
111
+ try {
112
+ removeGeneratedInfraFiles(projectDir);
113
+ local.stop("Generated local deploy artifacts removed");
114
+ }
115
+ catch (error) {
116
+ local.stop("Local cleanup failed");
117
+ const message = error instanceof Error ? error.message : "Unknown error";
118
+ p.log.warn(message);
119
+ }
120
+ p.outro(pc.green("Seamless destroy finished."));
121
+ }
122
+ //# sourceMappingURL=destroy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destroy.js","sourceRoot":"","sources":["../../src/commands/destroy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { VERSION } from "../index.js";
2
+ export function printHelp() {
3
+ console.log(`
4
+ seamless v${VERSION}
5
+
6
+ Seamless CLI — scaffold and manage full-stack authentication systems.
7
+
8
+ ────────────────────────────────────────────
9
+
10
+ USAGE
11
+
12
+ seamless init [project-name]
13
+ seamless check
14
+ seamless bootstrap-admin [email]
15
+ seamless --help
16
+ seamless --version
17
+
18
+ ────────────────────────────────────────────
19
+
20
+ COMMANDS
21
+
22
+ init [project-name]
23
+ Scaffold a new Seamless Auth project
24
+
25
+ Without a name:
26
+ • Creates project in current directory
27
+
28
+ With a name:
29
+ • Creates new directory
30
+
31
+ check
32
+ Validate project setup, Docker, and running services
33
+
34
+ bootstrap-admin [email]
35
+ Create a bootstrap admin invite
36
+
37
+ Automatically resolves bootstrap secret from:
38
+ • .env
39
+ • auth/.env
40
+ • docker-compose.yml
41
+
42
+ If not found, you will be prompted.
43
+
44
+ Examples:
45
+ seamless bootstrap-admin
46
+ seamless bootstrap-admin admin@example.com
47
+
48
+ ────────────────────────────────────────────
49
+
50
+ BEHAVIOR
51
+
52
+ seamless <project-name>
53
+
54
+ • Shortcut for: seamless init <project-name>
55
+
56
+ ────────────────────────────────────────────
57
+
58
+ GETTING STARTED
59
+
60
+ 1. seamless init
61
+ 2. docker-compose up
62
+ 3. seamless bootstrap-admin
63
+
64
+ → Complete registration to become admin
65
+
66
+ ────────────────────────────────────────────
67
+
68
+ WHAT YOU GET
69
+
70
+ • Web application (React starter)
71
+ • API server (Express)
72
+ • SeamlessAuth server (Docker or local)
73
+ • Admin dashboard (Docker or source)
74
+ • Docker Compose setup
75
+
76
+ ────────────────────────────────────────────
77
+
78
+ EXAMPLES
79
+
80
+ seamless init
81
+ → Interactive setup in current directory
82
+
83
+ seamless init my-app
84
+ → Create new project in ./my-app
85
+
86
+ seamless my-app
87
+ → Shortcut for init
88
+
89
+ seamless check
90
+ → Validate your project
91
+
92
+ seamless bootstrap-admin
93
+ → Create your first admin user
94
+
95
+ ────────────────────────────────────────────
96
+
97
+ DOCS
98
+
99
+ https://docs.seamlessauth.com
100
+
101
+ `);
102
+ }
103
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,CAAC;YACF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGlB,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,73 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { runProjectSetupPrompts } from "../prompts/projectSetup.js";
4
+ import { generateReactStarter } from "../generators/frontend/react.js";
5
+ import { generateExpressStarter } from "../generators/backend/express.js";
6
+ import { generateAuthServer } from "../generators/auth/auth.js";
7
+ import { configureApiEnv, configureWebEnv } from "../core/configure.js";
8
+ import { configureAuthLocalEnv, generateDockerCompose, } from "../generators/docker/docker.js";
9
+ import { printSuccessOutput } from "../core/output.js";
10
+ import { generateSeamlessConfig } from "../generators/config/config.js";
11
+ export async function runCLI(projectName) {
12
+ const cwd = process.cwd();
13
+ let root = cwd;
14
+ if (projectName) {
15
+ root = path.join(cwd, projectName);
16
+ if (fs.existsSync(root)) {
17
+ throw new Error(`Directory already exists: ${projectName}`);
18
+ }
19
+ fs.mkdirSync(root);
20
+ console.log(`Creating project in ${root}`);
21
+ }
22
+ const files = fs.readdirSync(root);
23
+ const isEmpty = files.length === 0;
24
+ if (!isEmpty) {
25
+ console.log("Existing project detected.");
26
+ console.log("Integration flow coming next.");
27
+ return;
28
+ }
29
+ const answers = await runProjectSetupPrompts();
30
+ if (answers.web && answers.webFramework === "react") {
31
+ await generateReactStarter({ root });
32
+ }
33
+ if (answers.api && answers.apiFramework === "express") {
34
+ await generateExpressStarter({ root });
35
+ }
36
+ let sharedConfig = {};
37
+ if (answers.authMode === "local") {
38
+ await generateAuthServer({ root }, "local");
39
+ sharedConfig = await configureAuthLocalEnv(root);
40
+ }
41
+ if (answers.useDocker) {
42
+ const dockerShared = await generateDockerCompose(root, {
43
+ authMode: answers.authMode,
44
+ adminMode: answers.adminMode,
45
+ includeAdmin: answers.includeAdmin,
46
+ });
47
+ if (answers.authMode === "docker") {
48
+ sharedConfig = dockerShared;
49
+ }
50
+ }
51
+ if (answers.api) {
52
+ configureApiEnv(root, sharedConfig);
53
+ }
54
+ if (answers.web) {
55
+ configureWebEnv(root);
56
+ }
57
+ generateSeamlessConfig(root, {
58
+ projectName,
59
+ webFramework: answers.webFramework,
60
+ apiFramework: answers.apiFramework,
61
+ authMode: answers.authMode,
62
+ adminMode: answers.adminMode,
63
+ });
64
+ printSuccessOutput({
65
+ projectName,
66
+ root,
67
+ webFramework: answers.webFramework,
68
+ apiFramework: answers.apiFramework,
69
+ authMode: answers.authMode,
70
+ useDocker: answers.useDocker,
71
+ });
72
+ }
73
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ const siblingRoot = path.resolve(process.cwd(), "..");
4
+ export const CONTRIBUTOR_COMPONENTS = [
5
+ {
6
+ id: "seamless-auth-api",
7
+ label: "seamless-auth-api",
8
+ description: "Public passwordless auth server",
9
+ publicSurface: "ghcr-image",
10
+ publicRef: "ghcr.io/fells-code/seamless-auth-api:latest",
11
+ gitUrl: "https://github.com/fells-code/seamless-auth-api.git",
12
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-api"),
13
+ workspaceDir: "repos/seamless-auth-api",
14
+ },
15
+ {
16
+ id: "seamless-auth-admin-dashboard",
17
+ label: "seamless-auth-admin-dashboard",
18
+ description: "Admin dashboard",
19
+ publicSurface: "ghcr-image",
20
+ publicRef: "ghcr.io/fells-code/seamless-auth-admin-dashboard:latest",
21
+ gitUrl: "https://github.com/fells-code/seamless-auth-admin-dashboard.git",
22
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-admin-dashboard"),
23
+ workspaceDir: "repos/seamless-auth-admin-dashboard",
24
+ },
25
+ {
26
+ id: "seamless-auth-react",
27
+ label: "seamless-auth-react",
28
+ description: "React SDK",
29
+ publicSurface: "npm-package",
30
+ publicRef: "@seamless-auth/react",
31
+ gitUrl: "https://github.com/fells-code/seamless-auth-react.git",
32
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-react"),
33
+ workspaceDir: "repos/seamless-auth-react",
34
+ localPackages: [{ packageName: "@seamless-auth/react" }],
35
+ },
36
+ {
37
+ id: "seamless-auth-server",
38
+ label: "seamless-auth-server",
39
+ description: "Server-side integration SDKs",
40
+ publicSurface: "npm-package",
41
+ publicRef: ["@seamless-auth/core", "@seamless-auth/express"],
42
+ gitUrl: "https://github.com/fells-code/seamless-auth-server.git",
43
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-server"),
44
+ workspaceDir: "repos/seamless-auth-server",
45
+ localPackages: [
46
+ {
47
+ packageName: "@seamless-auth/core",
48
+ relativePath: "packages/core",
49
+ },
50
+ {
51
+ packageName: "@seamless-auth/express",
52
+ relativePath: "packages/express",
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ id: "seamless-messaging",
58
+ label: "seamless-messaging",
59
+ description: "Messaging package family",
60
+ publicSurface: "npm-package",
61
+ publicRef: [
62
+ "@seamless-auth/messaging",
63
+ "@seamless-auth/messaging-aws",
64
+ "@seamless-auth/messaging-twilio",
65
+ ],
66
+ gitUrl: "https://github.com/fells-code/seamless-messaging.git",
67
+ localSiblingPath: path.join(siblingRoot, "seamless-messaging"),
68
+ workspaceDir: "repos/seamless-messaging",
69
+ localPackages: [
70
+ {
71
+ packageName: "@seamless-auth/messaging",
72
+ relativePath: "packages/core",
73
+ },
74
+ {
75
+ packageName: "@seamless-auth/messaging-aws",
76
+ relativePath: "packages/aws",
77
+ },
78
+ {
79
+ packageName: "@seamless-auth/messaging-twilio",
80
+ relativePath: "packages/twilio",
81
+ },
82
+ ],
83
+ },
84
+ {
85
+ id: "seamless-auth-starter-express",
86
+ label: "seamless-auth-starter-express",
87
+ description: "Express starter app",
88
+ publicSurface: "github-repo",
89
+ publicRef: "https://github.com/fells-code/seamless-auth-starter-express",
90
+ gitUrl: "https://github.com/fells-code/seamless-auth-starter-express.git",
91
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-starter-express"),
92
+ workspaceDir: "repos/seamless-auth-starter-express",
93
+ publicWorkspaceDir: "examples/seamless-auth-starter-express",
94
+ },
95
+ {
96
+ id: "seamless-auth-starter-react",
97
+ label: "seamless-auth-starter-react",
98
+ description: "React starter app",
99
+ publicSurface: "github-repo",
100
+ publicRef: "https://github.com/fells-code/seamless-auth-starter-react",
101
+ gitUrl: "https://github.com/fells-code/seamless-auth-starter-react.git",
102
+ localSiblingPath: path.join(siblingRoot, "seamless-auth-starter-react"),
103
+ workspaceDir: "repos/seamless-auth-starter-react",
104
+ publicWorkspaceDir: "examples/seamless-auth-starter-react",
105
+ },
106
+ ];
107
+ export function getContributorComponent(id) {
108
+ const component = CONTRIBUTOR_COMPONENTS.find((entry) => entry.id === id);
109
+ if (!component) {
110
+ throw new Error(`Unknown contributor component: ${id}`);
111
+ }
112
+ return component;
113
+ }
114
+ export function formatPublicRef(ref) {
115
+ return Array.isArray(ref) ? ref.join(", ") : ref;
116
+ }
117
+ export function resolveCloneSource(component) {
118
+ if (component.localSiblingPath && fs.existsSync(component.localSiblingPath)) {
119
+ return component.localSiblingPath;
120
+ }
121
+ return component.gitUrl;
122
+ }
123
+ export function resolveWorkspaceDir(component, mode) {
124
+ if (mode === "local") {
125
+ return component.workspaceDir;
126
+ }
127
+ return component.publicWorkspaceDir ?? component.workspaceDir;
128
+ }
129
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/contributor/catalog.ts"],"names":[],"mappings":"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"}