create-aws-project 1.2.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 (181) hide show
  1. package/README.md +118 -0
  2. package/dist/__tests__/generator/replace-tokens.spec.d.ts +1 -0
  3. package/dist/__tests__/generator/replace-tokens.spec.js +281 -0
  4. package/dist/__tests__/generator.spec.d.ts +1 -0
  5. package/dist/__tests__/generator.spec.js +162 -0
  6. package/dist/__tests__/validation/project-name.spec.d.ts +1 -0
  7. package/dist/__tests__/validation/project-name.spec.js +57 -0
  8. package/dist/__tests__/wizard.spec.d.ts +1 -0
  9. package/dist/__tests__/wizard.spec.js +232 -0
  10. package/dist/aws/iam.d.ts +75 -0
  11. package/dist/aws/iam.js +264 -0
  12. package/dist/aws/organizations.d.ts +79 -0
  13. package/dist/aws/organizations.js +168 -0
  14. package/dist/cli.d.ts +4 -0
  15. package/dist/cli.js +206 -0
  16. package/dist/commands/setup-github.d.ts +4 -0
  17. package/dist/commands/setup-github.js +185 -0
  18. package/dist/generator/copy-file.d.ts +15 -0
  19. package/dist/generator/copy-file.js +56 -0
  20. package/dist/generator/generate-project.d.ts +14 -0
  21. package/dist/generator/generate-project.js +81 -0
  22. package/dist/generator/index.d.ts +4 -0
  23. package/dist/generator/index.js +3 -0
  24. package/dist/generator/replace-tokens.d.ts +29 -0
  25. package/dist/generator/replace-tokens.js +68 -0
  26. package/dist/github/secrets.d.ts +109 -0
  27. package/dist/github/secrets.js +275 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +6 -0
  30. package/dist/prompts/auth.d.ts +3 -0
  31. package/dist/prompts/auth.js +23 -0
  32. package/dist/prompts/aws-config.d.ts +2 -0
  33. package/dist/prompts/aws-config.js +14 -0
  34. package/dist/prompts/features.d.ts +2 -0
  35. package/dist/prompts/features.js +10 -0
  36. package/dist/prompts/github-setup.d.ts +53 -0
  37. package/dist/prompts/github-setup.js +208 -0
  38. package/dist/prompts/org-structure.d.ts +9 -0
  39. package/dist/prompts/org-structure.js +93 -0
  40. package/dist/prompts/platforms.d.ts +2 -0
  41. package/dist/prompts/platforms.js +12 -0
  42. package/dist/prompts/project-name.d.ts +2 -0
  43. package/dist/prompts/project-name.js +8 -0
  44. package/dist/prompts/theme.d.ts +2 -0
  45. package/dist/prompts/theme.js +14 -0
  46. package/dist/templates/index.d.ts +4 -0
  47. package/dist/templates/index.js +2 -0
  48. package/dist/templates/manifest.d.ts +11 -0
  49. package/dist/templates/manifest.js +99 -0
  50. package/dist/templates/tokens.d.ts +39 -0
  51. package/dist/templates/tokens.js +37 -0
  52. package/dist/templates/types.d.ts +52 -0
  53. package/dist/templates/types.js +1 -0
  54. package/dist/types.d.ts +27 -0
  55. package/dist/types.js +1 -0
  56. package/dist/validation/project-name.d.ts +1 -0
  57. package/dist/validation/project-name.js +12 -0
  58. package/dist/wizard.d.ts +2 -0
  59. package/dist/wizard.js +81 -0
  60. package/package.json +68 -0
  61. package/templates/.github/actions/build-and-test/action.yml +24 -0
  62. package/templates/.github/actions/deploy-cdk/action.yml +46 -0
  63. package/templates/.github/actions/deploy-web/action.yml +72 -0
  64. package/templates/.github/actions/setup/action.yml +29 -0
  65. package/templates/.github/pull_request_template.md +15 -0
  66. package/templates/.github/workflows/deploy-dev.yml +80 -0
  67. package/templates/.github/workflows/deploy-prod.yml +67 -0
  68. package/templates/.github/workflows/deploy-stage.yml +77 -0
  69. package/templates/.github/workflows/pull-request.yml +72 -0
  70. package/templates/.vscode/extensions.json +7 -0
  71. package/templates/.vscode/settings.json +67 -0
  72. package/templates/apps/api/.eslintrc.json +18 -0
  73. package/templates/apps/api/cdk/app.ts +93 -0
  74. package/templates/apps/api/cdk/auth/cognito-stack.ts +164 -0
  75. package/templates/apps/api/cdk/cdk.json +73 -0
  76. package/templates/apps/api/cdk/deployment-user-stack.ts +187 -0
  77. package/templates/apps/api/cdk/org-stack.ts +67 -0
  78. package/templates/apps/api/cdk/static-stack.ts +361 -0
  79. package/templates/apps/api/cdk/tsconfig.json +39 -0
  80. package/templates/apps/api/cdk/user-stack.ts +255 -0
  81. package/templates/apps/api/jest.config.ts +38 -0
  82. package/templates/apps/api/lambdas.yml +84 -0
  83. package/templates/apps/api/project.json.template +58 -0
  84. package/templates/apps/api/src/__tests__/setup.ts +10 -0
  85. package/templates/apps/api/src/handlers/users/create-user.ts +52 -0
  86. package/templates/apps/api/src/handlers/users/delete-user.ts +45 -0
  87. package/templates/apps/api/src/handlers/users/get-me.ts +72 -0
  88. package/templates/apps/api/src/handlers/users/get-user.ts +45 -0
  89. package/templates/apps/api/src/handlers/users/get-users.ts +23 -0
  90. package/templates/apps/api/src/handlers/users/index.ts +17 -0
  91. package/templates/apps/api/src/handlers/users/update-user.ts +72 -0
  92. package/templates/apps/api/src/lib/dynamo/dynamo-model.ts +504 -0
  93. package/templates/apps/api/src/lib/dynamo/index.ts +12 -0
  94. package/templates/apps/api/src/lib/dynamo/utils.ts +39 -0
  95. package/templates/apps/api/src/middleware/auth0-auth.ts +97 -0
  96. package/templates/apps/api/src/middleware/cognito-auth.ts +90 -0
  97. package/templates/apps/api/src/models/UserModel.ts +109 -0
  98. package/templates/apps/api/src/schemas/user.schema.ts +44 -0
  99. package/templates/apps/api/src/services/user-service.ts +108 -0
  100. package/templates/apps/api/src/utils/auth-context.ts +60 -0
  101. package/templates/apps/api/src/utils/common/helpers.ts +26 -0
  102. package/templates/apps/api/src/utils/lambda-handler.ts +148 -0
  103. package/templates/apps/api/src/utils/response.ts +52 -0
  104. package/templates/apps/api/src/utils/validator.ts +75 -0
  105. package/templates/apps/api/tsconfig.app.json +15 -0
  106. package/templates/apps/api/tsconfig.json +19 -0
  107. package/templates/apps/api/tsconfig.spec.json +17 -0
  108. package/templates/apps/mobile/.env.example +5 -0
  109. package/templates/apps/mobile/.eslintrc.json +33 -0
  110. package/templates/apps/mobile/app.json +33 -0
  111. package/templates/apps/mobile/assets/.gitkeep +0 -0
  112. package/templates/apps/mobile/babel.config.js +19 -0
  113. package/templates/apps/mobile/index.js +7 -0
  114. package/templates/apps/mobile/jest.config.ts +22 -0
  115. package/templates/apps/mobile/metro.config.js +35 -0
  116. package/templates/apps/mobile/package.json +22 -0
  117. package/templates/apps/mobile/project.json.template +64 -0
  118. package/templates/apps/mobile/src/App.tsx +367 -0
  119. package/templates/apps/mobile/src/__tests__/App.spec.tsx +46 -0
  120. package/templates/apps/mobile/src/__tests__/store/user-store.spec.ts +156 -0
  121. package/templates/apps/mobile/src/config/api.ts +16 -0
  122. package/templates/apps/mobile/src/store/user-store.ts +56 -0
  123. package/templates/apps/mobile/src/test-setup.ts +10 -0
  124. package/templates/apps/mobile/tsconfig.json +22 -0
  125. package/templates/apps/web/.env.example +13 -0
  126. package/templates/apps/web/.eslintrc.json +26 -0
  127. package/templates/apps/web/index.html +13 -0
  128. package/templates/apps/web/jest.config.ts +24 -0
  129. package/templates/apps/web/package.json +15 -0
  130. package/templates/apps/web/project.json.template +66 -0
  131. package/templates/apps/web/src/App.tsx +352 -0
  132. package/templates/apps/web/src/__mocks__/config/api.ts +41 -0
  133. package/templates/apps/web/src/__tests__/App.spec.tsx +240 -0
  134. package/templates/apps/web/src/__tests__/store/user-store.spec.ts +185 -0
  135. package/templates/apps/web/src/auth/auth0-provider.tsx +103 -0
  136. package/templates/apps/web/src/auth/cognito-provider.tsx +143 -0
  137. package/templates/apps/web/src/auth/index.ts +7 -0
  138. package/templates/apps/web/src/auth/use-auth.ts +16 -0
  139. package/templates/apps/web/src/config/amplify-config.ts +31 -0
  140. package/templates/apps/web/src/config/api.ts +38 -0
  141. package/templates/apps/web/src/config/auth0-config.ts +17 -0
  142. package/templates/apps/web/src/main.tsx +41 -0
  143. package/templates/apps/web/src/store/user-store.ts +56 -0
  144. package/templates/apps/web/src/styles.css +165 -0
  145. package/templates/apps/web/src/test-setup.ts +1 -0
  146. package/templates/apps/web/src/theme/index.ts +30 -0
  147. package/templates/apps/web/src/vite-env.d.ts +19 -0
  148. package/templates/apps/web/tsconfig.app.json +24 -0
  149. package/templates/apps/web/tsconfig.json +22 -0
  150. package/templates/apps/web/tsconfig.spec.json +28 -0
  151. package/templates/apps/web/vite.config.ts +87 -0
  152. package/templates/manifest.json +28 -0
  153. package/templates/packages/api-client/.eslintrc.json +18 -0
  154. package/templates/packages/api-client/jest.config.ts +13 -0
  155. package/templates/packages/api-client/package.json +8 -0
  156. package/templates/packages/api-client/project.json.template +34 -0
  157. package/templates/packages/api-client/src/__tests__/api-client.spec.ts +408 -0
  158. package/templates/packages/api-client/src/api-client.ts +201 -0
  159. package/templates/packages/api-client/src/config.ts +193 -0
  160. package/templates/packages/api-client/src/index.ts +9 -0
  161. package/templates/packages/api-client/tsconfig.json +22 -0
  162. package/templates/packages/api-client/tsconfig.lib.json +11 -0
  163. package/templates/packages/api-client/tsconfig.spec.json +14 -0
  164. package/templates/packages/common-types/.eslintrc.json +18 -0
  165. package/templates/packages/common-types/package.json +6 -0
  166. package/templates/packages/common-types/project.json.template +26 -0
  167. package/templates/packages/common-types/src/api.types.ts +24 -0
  168. package/templates/packages/common-types/src/auth.types.ts +36 -0
  169. package/templates/packages/common-types/src/common.types.ts +46 -0
  170. package/templates/packages/common-types/src/index.ts +19 -0
  171. package/templates/packages/common-types/src/lambda.types.ts +39 -0
  172. package/templates/packages/common-types/src/user.types.ts +31 -0
  173. package/templates/packages/common-types/tsconfig.json +19 -0
  174. package/templates/packages/common-types/tsconfig.lib.json +11 -0
  175. package/templates/root/.editorconfig +23 -0
  176. package/templates/root/.nvmrc +1 -0
  177. package/templates/root/eslint.config.js +61 -0
  178. package/templates/root/jest.preset.js +16 -0
  179. package/templates/root/nx.json +29 -0
  180. package/templates/root/package.json +131 -0
  181. package/templates/root/tsconfig.base.json +29 -0
@@ -0,0 +1,53 @@
1
+ import type { PromptObject } from 'prompts';
2
+ /**
3
+ * GitHub setup prompts module
4
+ *
5
+ * Provides prompts for the setup-github command to collect
6
+ * configuration for IAM deployment users and GitHub secrets.
7
+ */
8
+ /**
9
+ * Configuration for an environment with AWS profile
10
+ */
11
+ export interface EnvironmentConfig {
12
+ environment: string;
13
+ accountId: string;
14
+ awsProfile: string;
15
+ }
16
+ /**
17
+ * Complete configuration from the GitHub setup wizard
18
+ */
19
+ export interface GitHubSetupConfig {
20
+ projectName: string;
21
+ awsRegion: string;
22
+ environments: EnvironmentConfig[];
23
+ github: {
24
+ owner: string;
25
+ repo: string;
26
+ token: string;
27
+ };
28
+ }
29
+ /**
30
+ * Project name prompt - used as prefix for IAM users
31
+ */
32
+ export declare const projectNamePrompt: PromptObject;
33
+ /**
34
+ * AWS region selection prompt
35
+ */
36
+ export declare const awsRegionPrompt: PromptObject;
37
+ /**
38
+ * Environments multiselect prompt
39
+ */
40
+ export declare const environmentsPrompt: PromptObject;
41
+ /**
42
+ * GitHub repository prompt - accepts various formats
43
+ */
44
+ export declare const githubRepoPrompt: PromptObject;
45
+ /**
46
+ * GitHub Personal Access Token prompt
47
+ */
48
+ export declare const githubTokenPrompt: PromptObject;
49
+ /**
50
+ * Runs the complete GitHub setup wizard
51
+ * @returns Configuration object or null if cancelled
52
+ */
53
+ export declare function runGitHubSetupWizard(): Promise<GitHubSetupConfig | null>;
@@ -0,0 +1,208 @@
1
+ import prompts from 'prompts';
2
+ /**
3
+ * Validates kebab-case project name
4
+ */
5
+ function isKebabCase(value) {
6
+ return /^[a-z][a-z0-9-]*[a-z0-9]$/.test(value) || /^[a-z]$/.test(value);
7
+ }
8
+ /**
9
+ * Project name prompt - used as prefix for IAM users
10
+ */
11
+ export const projectNamePrompt = {
12
+ type: 'text',
13
+ name: 'projectName',
14
+ message: 'Project name (used as prefix for IAM users):',
15
+ validate: (value) => {
16
+ if (!value.trim())
17
+ return 'Project name is required';
18
+ if (value.length > 20)
19
+ return 'Project name must be 20 characters or less';
20
+ if (!isKebabCase(value))
21
+ return 'Project name must be kebab-case (e.g., my-app)';
22
+ return true;
23
+ },
24
+ format: (value) => value.trim().toLowerCase(),
25
+ };
26
+ /**
27
+ * AWS region selection prompt
28
+ */
29
+ export const awsRegionPrompt = {
30
+ type: 'select',
31
+ name: 'awsRegion',
32
+ message: 'AWS Region:',
33
+ choices: [
34
+ { title: 'US East (N. Virginia) - us-east-1', value: 'us-east-1' },
35
+ { title: 'US West (Oregon) - us-west-2', value: 'us-west-2' },
36
+ { title: 'EU (Ireland) - eu-west-1', value: 'eu-west-1' },
37
+ { title: 'EU (Frankfurt) - eu-central-1', value: 'eu-central-1' },
38
+ { title: 'Asia Pacific (Tokyo) - ap-northeast-1', value: 'ap-northeast-1' },
39
+ { title: 'Asia Pacific (Sydney) - ap-southeast-2', value: 'ap-southeast-2' },
40
+ ],
41
+ initial: 0,
42
+ };
43
+ /**
44
+ * Environments multiselect prompt
45
+ */
46
+ export const environmentsPrompt = {
47
+ type: 'multiselect',
48
+ name: 'environments',
49
+ message: 'Select environments to configure:',
50
+ choices: [
51
+ { title: 'dev', value: 'dev', selected: true },
52
+ { title: 'stage', value: 'stage', selected: true },
53
+ { title: 'prod', value: 'prod', selected: true },
54
+ ],
55
+ hint: '- Space to toggle, Enter to confirm',
56
+ min: 1,
57
+ };
58
+ /**
59
+ * Validates 12-digit AWS account ID
60
+ */
61
+ function isValidAccountId(value) {
62
+ return /^\d{12}$/.test(value);
63
+ }
64
+ /**
65
+ * Creates account ID prompt for a specific environment
66
+ */
67
+ function createAccountIdPrompt(environment) {
68
+ return {
69
+ type: 'text',
70
+ name: `accountId_${environment}`,
71
+ message: `AWS Account ID for ${environment}:`,
72
+ validate: (value) => {
73
+ if (!value.trim())
74
+ return 'Account ID is required';
75
+ if (!isValidAccountId(value.trim()))
76
+ return 'Account ID must be a 12-digit number';
77
+ return true;
78
+ },
79
+ format: (value) => value.trim(),
80
+ };
81
+ }
82
+ /**
83
+ * Creates AWS profile prompt for a specific environment
84
+ */
85
+ function createAwsProfilePrompt(environment) {
86
+ return {
87
+ type: 'text',
88
+ name: `awsProfile_${environment}`,
89
+ message: `AWS profile for ${environment} account:`,
90
+ initial: 'default',
91
+ format: (value) => value.trim() || 'default',
92
+ };
93
+ }
94
+ /**
95
+ * GitHub repository prompt - accepts various formats
96
+ */
97
+ export const githubRepoPrompt = {
98
+ type: 'text',
99
+ name: 'githubRepo',
100
+ message: 'GitHub repository (owner/repo or URL):',
101
+ validate: (value) => {
102
+ if (!value.trim())
103
+ return 'Repository is required';
104
+ // Try to parse the URL to validate format
105
+ const trimmed = value.trim();
106
+ const cleanUrl = trimmed.replace(/\/$/, '').replace(/\.git$/, '');
107
+ // Check supported formats
108
+ const httpsMatch = cleanUrl.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)$/);
109
+ const sshMatch = cleanUrl.match(/^git@github\.com:([^/]+)\/([^/]+)$/);
110
+ const shortMatch = cleanUrl.match(/^([^/]+)\/([^/]+)$/);
111
+ if (!httpsMatch && !sshMatch && !shortMatch) {
112
+ return 'Invalid format. Use: owner/repo, https://github.com/owner/repo, or git@github.com:owner/repo';
113
+ }
114
+ return true;
115
+ },
116
+ format: (value) => value.trim(),
117
+ };
118
+ /**
119
+ * GitHub Personal Access Token prompt
120
+ */
121
+ export const githubTokenPrompt = {
122
+ type: 'password',
123
+ name: 'githubToken',
124
+ message: 'GitHub Personal Access Token (requires "repo" scope):',
125
+ validate: (value) => {
126
+ if (!value.trim())
127
+ return 'Token is required';
128
+ return true;
129
+ },
130
+ };
131
+ /**
132
+ * Parses GitHub repository string to owner/repo
133
+ */
134
+ function parseGitHubRepo(url) {
135
+ const cleanUrl = url.trim().replace(/\/$/, '').replace(/\.git$/, '');
136
+ // Format: https://github.com/owner/repo
137
+ const httpsMatch = cleanUrl.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)$/);
138
+ if (httpsMatch) {
139
+ return { owner: httpsMatch[1], repo: httpsMatch[2] };
140
+ }
141
+ // Format: git@github.com:owner/repo
142
+ const sshMatch = cleanUrl.match(/^git@github\.com:([^/]+)\/([^/]+)$/);
143
+ if (sshMatch) {
144
+ return { owner: sshMatch[1], repo: sshMatch[2] };
145
+ }
146
+ // Format: owner/repo
147
+ const shortMatch = cleanUrl.match(/^([^/]+)\/([^/]+)$/);
148
+ if (shortMatch) {
149
+ return { owner: shortMatch[1], repo: shortMatch[2] };
150
+ }
151
+ throw new Error(`Unable to parse GitHub URL: ${url}`);
152
+ }
153
+ /**
154
+ * Runs the complete GitHub setup wizard
155
+ * @returns Configuration object or null if cancelled
156
+ */
157
+ export async function runGitHubSetupWizard() {
158
+ let cancelled = false;
159
+ const onCancel = () => {
160
+ cancelled = true;
161
+ return false;
162
+ };
163
+ // Step 1: Basic configuration
164
+ const basicResponse = await prompts([projectNamePrompt, awsRegionPrompt, environmentsPrompt], { onCancel });
165
+ if (cancelled || !basicResponse.projectName || !basicResponse.environments?.length) {
166
+ return null;
167
+ }
168
+ const selectedEnvironments = basicResponse.environments;
169
+ // Step 2: Account IDs and AWS profiles for each environment
170
+ const environmentPrompts = [];
171
+ for (const env of selectedEnvironments) {
172
+ environmentPrompts.push(createAccountIdPrompt(env));
173
+ environmentPrompts.push(createAwsProfilePrompt(env));
174
+ }
175
+ const environmentResponse = await prompts(environmentPrompts, { onCancel });
176
+ if (cancelled) {
177
+ return null;
178
+ }
179
+ // Validate all environment data was collected
180
+ for (const env of selectedEnvironments) {
181
+ if (!environmentResponse[`accountId_${env}`]) {
182
+ return null;
183
+ }
184
+ }
185
+ // Step 3: GitHub configuration
186
+ const githubResponse = await prompts([githubRepoPrompt, githubTokenPrompt], { onCancel });
187
+ if (cancelled || !githubResponse.githubRepo || !githubResponse.githubToken) {
188
+ return null;
189
+ }
190
+ // Parse GitHub repo
191
+ const { owner, repo } = parseGitHubRepo(githubResponse.githubRepo);
192
+ // Build environments array
193
+ const environments = selectedEnvironments.map((env) => ({
194
+ environment: env,
195
+ accountId: environmentResponse[`accountId_${env}`],
196
+ awsProfile: environmentResponse[`awsProfile_${env}`] || 'default',
197
+ }));
198
+ return {
199
+ projectName: basicResponse.projectName,
200
+ awsRegion: basicResponse.awsRegion,
201
+ environments,
202
+ github: {
203
+ owner,
204
+ repo,
205
+ token: githubResponse.githubToken,
206
+ },
207
+ };
208
+ }
@@ -0,0 +1,9 @@
1
+ import type { PromptObject } from 'prompts';
2
+ export declare const enableOrgPrompt: PromptObject;
3
+ export declare const orgNamePrompt: PromptObject;
4
+ export declare const orgEnvironmentsPrompt: PromptObject;
5
+ export declare const devEmailPrompt: PromptObject;
6
+ export declare const stageEmailPrompt: PromptObject;
7
+ export declare const prodEmailPrompt: PromptObject;
8
+ export declare const qaEmailPrompt: PromptObject;
9
+ export declare const sandboxEmailPrompt: PromptObject;
@@ -0,0 +1,93 @@
1
+ import pc from 'picocolors';
2
+ export const enableOrgPrompt = {
3
+ type: 'select',
4
+ name: 'enableOrg',
5
+ message: 'Set up AWS Organizations with separate accounts per environment?',
6
+ choices: [
7
+ { title: `${pc.yellow('○')} No (single account)`, value: false },
8
+ { title: `${pc.cyan('◆')} Yes (multi-account)`, value: true },
9
+ ],
10
+ initial: 0,
11
+ hint: '- Creates separate AWS accounts for each environment'
12
+ };
13
+ export const orgNamePrompt = {
14
+ type: (prev) => prev ? 'text' : null,
15
+ name: 'orgName',
16
+ message: 'Organization name:',
17
+ initial: (_prev, values) => `${values.projectName}-org`,
18
+ validate: (value) => value.trim().length > 0 || 'Organization name is required'
19
+ };
20
+ export const orgEnvironmentsPrompt = {
21
+ type: (_prev, values) => values.enableOrg ? 'multiselect' : null,
22
+ name: 'orgEnvironments',
23
+ message: 'Select environments to create accounts for:',
24
+ choices: [
25
+ { title: 'dev', value: 'dev', selected: true },
26
+ { title: 'stage', value: 'stage', selected: true },
27
+ { title: 'prod', value: 'prod', selected: true },
28
+ { title: 'qa', value: 'qa', selected: false },
29
+ { title: 'sandbox', value: 'sandbox', selected: false },
30
+ ],
31
+ hint: '- Space to toggle, Enter to confirm',
32
+ min: 1
33
+ };
34
+ export const devEmailPrompt = {
35
+ type: (_prev, values) => values.enableOrg && values.orgEnvironments?.includes('dev') ? 'text' : null,
36
+ name: 'devEmail',
37
+ message: 'Dev account root email:',
38
+ validate: (value) => {
39
+ if (!value.trim())
40
+ return 'Email is required';
41
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
42
+ return 'Invalid email format';
43
+ return true;
44
+ }
45
+ };
46
+ export const stageEmailPrompt = {
47
+ type: (_prev, values) => values.enableOrg && values.orgEnvironments?.includes('stage') ? 'text' : null,
48
+ name: 'stageEmail',
49
+ message: 'Stage account root email:',
50
+ validate: (value) => {
51
+ if (!value.trim())
52
+ return 'Email is required';
53
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
54
+ return 'Invalid email format';
55
+ return true;
56
+ }
57
+ };
58
+ export const prodEmailPrompt = {
59
+ type: (_prev, values) => values.enableOrg && values.orgEnvironments?.includes('prod') ? 'text' : null,
60
+ name: 'prodEmail',
61
+ message: 'Prod account root email:',
62
+ validate: (value) => {
63
+ if (!value.trim())
64
+ return 'Email is required';
65
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
66
+ return 'Invalid email format';
67
+ return true;
68
+ }
69
+ };
70
+ export const qaEmailPrompt = {
71
+ type: (_prev, values) => values.enableOrg && values.orgEnvironments?.includes('qa') ? 'text' : null,
72
+ name: 'qaEmail',
73
+ message: 'QA account root email:',
74
+ validate: (value) => {
75
+ if (!value.trim())
76
+ return 'Email is required';
77
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
78
+ return 'Invalid email format';
79
+ return true;
80
+ }
81
+ };
82
+ export const sandboxEmailPrompt = {
83
+ type: (_prev, values) => values.enableOrg && values.orgEnvironments?.includes('sandbox') ? 'text' : null,
84
+ name: 'sandboxEmail',
85
+ message: 'Sandbox account root email:',
86
+ validate: (value) => {
87
+ if (!value.trim())
88
+ return 'Email is required';
89
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
90
+ return 'Invalid email format';
91
+ return true;
92
+ }
93
+ };
@@ -0,0 +1,2 @@
1
+ import type { PromptObject } from 'prompts';
2
+ export declare const platformsPrompt: PromptObject;
@@ -0,0 +1,12 @@
1
+ export const platformsPrompt = {
2
+ type: 'multiselect',
3
+ name: 'platforms',
4
+ message: 'Select platforms (space to toggle, enter to confirm):',
5
+ choices: [
6
+ { title: 'Web (React + Vite + Chakra UI)', value: 'web', selected: true },
7
+ { title: 'Mobile (React Native + Expo)', value: 'mobile' },
8
+ { title: 'API (AWS Lambda + DynamoDB)', value: 'api', selected: true }
9
+ ],
10
+ min: 1,
11
+ hint: '- At least one required'
12
+ };
@@ -0,0 +1,2 @@
1
+ import type { PromptObject } from 'prompts';
2
+ export declare const projectNamePrompt: PromptObject;
@@ -0,0 +1,8 @@
1
+ import { validateProjectName } from '../validation/project-name.js';
2
+ export const projectNamePrompt = {
3
+ type: 'text',
4
+ name: 'projectName',
5
+ message: 'Project name:',
6
+ initial: 'my-aws-app',
7
+ validate: (value) => validateProjectName(value)
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { PromptObject } from 'prompts';
2
+ export declare const themePrompt: PromptObject;
@@ -0,0 +1,14 @@
1
+ import pc from 'picocolors';
2
+ export const themePrompt = {
3
+ type: 'select',
4
+ name: 'brandColor',
5
+ message: 'Choose your brand color:',
6
+ choices: [
7
+ { title: `${pc.blue('●')} Blue`, value: 'blue' },
8
+ { title: `${pc.magenta('●')} Purple`, value: 'purple' },
9
+ { title: `${pc.cyan('●')} Teal`, value: 'teal' },
10
+ { title: `${pc.green('●')} Green`, value: 'green' },
11
+ { title: `${pc.yellow('●')} Orange`, value: 'orange' }
12
+ ],
13
+ initial: 0
14
+ };
@@ -0,0 +1,4 @@
1
+ export { TOKENS, TOKEN_PATTERN } from './tokens.js';
2
+ export type { TokenName } from './tokens.js';
3
+ export type { TokenValues, Platform, TemplateFile, TemplateManifest, DeriveTokenValues, } from './types.js';
4
+ export { deriveTokenValues, templateManifest } from './manifest.js';
@@ -0,0 +1,2 @@
1
+ export { TOKENS, TOKEN_PATTERN } from './tokens.js';
2
+ export { deriveTokenValues, templateManifest } from './manifest.js';
@@ -0,0 +1,11 @@
1
+ import type { ProjectConfig } from '../types.js';
2
+ import type { TokenValues, TemplateManifest } from './types.js';
3
+ /**
4
+ * Derive all token values from user's ProjectConfig
5
+ */
6
+ export declare function deriveTokenValues(config: ProjectConfig): TokenValues;
7
+ /**
8
+ * Template manifest defining shared and platform-specific files
9
+ * This matches the structure in templates/manifest.json
10
+ */
11
+ export declare const templateManifest: TemplateManifest;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Convert kebab-case to PascalCase
3
+ * my-awesome-app -> MyAwesomeApp
4
+ */
5
+ function toPascalCase(str) {
6
+ return str
7
+ .split('-')
8
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
9
+ .join('');
10
+ }
11
+ /**
12
+ * Convert kebab-case to Title Case
13
+ * my-awesome-app -> My Awesome App
14
+ */
15
+ function toTitleCase(str) {
16
+ return str
17
+ .split('-')
18
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
19
+ .join(' ');
20
+ }
21
+ /**
22
+ * Find account ID for a specific environment name
23
+ */
24
+ function findAccountIdByEnvironment(accounts, environment) {
25
+ const account = accounts?.find((a) => a.environment.toLowerCase() === environment.toLowerCase());
26
+ return account?.accountId ?? '';
27
+ }
28
+ /**
29
+ * Derive all token values from user's ProjectConfig
30
+ */
31
+ export function deriveTokenValues(config) {
32
+ // Build organization accounts JSON for flexible environment handling
33
+ const orgAccounts = config.org?.accounts?.map((a) => ({
34
+ environment: a.environment,
35
+ accountId: a.accountId ?? '',
36
+ })) ?? [];
37
+ return {
38
+ PROJECT_NAME: config.projectName,
39
+ PROJECT_NAME_PASCAL: toPascalCase(config.projectName),
40
+ PROJECT_NAME_TITLE: toTitleCase(config.projectName),
41
+ AWS_REGION: config.awsRegion,
42
+ PACKAGE_SCOPE: `@${config.projectName}`,
43
+ BRAND_COLOR: config.brandColor,
44
+ AUTH_COGNITO: config.auth.provider === 'cognito' ? 'true' : 'false',
45
+ AUTH_AUTH0: config.auth.provider === 'auth0' ? 'true' : 'false',
46
+ AUTH_SOCIAL_LOGIN: config.auth.features.includes('social-login') ? 'true' : 'false',
47
+ AUTH_MFA: config.auth.features.includes('mfa') ? 'true' : 'false',
48
+ // Organization tokens
49
+ ORG_ENABLED: config.org?.enabled ? 'true' : 'false',
50
+ ORG_NAME: config.org?.organizationName ?? '',
51
+ ORG_ACCOUNTS_JSON: JSON.stringify(orgAccounts),
52
+ // Common environment account IDs for backward compatibility
53
+ DEV_ACCOUNT_ID: findAccountIdByEnvironment(config.org?.accounts, 'dev'),
54
+ STAGE_ACCOUNT_ID: findAccountIdByEnvironment(config.org?.accounts, 'stage'),
55
+ PROD_ACCOUNT_ID: findAccountIdByEnvironment(config.org?.accounts, 'prod'),
56
+ };
57
+ }
58
+ /**
59
+ * Template manifest defining shared and platform-specific files
60
+ * This matches the structure in templates/manifest.json
61
+ */
62
+ export const templateManifest = {
63
+ shared: [
64
+ { src: 'root/package.json', dest: 'package.json' },
65
+ { src: 'root/tsconfig.base.json', dest: 'tsconfig.base.json' },
66
+ { src: 'root/nx.json', dest: 'nx.json' },
67
+ { src: 'root/jest.preset.js', dest: 'jest.preset.js' },
68
+ { src: 'root/eslint.config.js', dest: 'eslint.config.js' },
69
+ { src: 'root/.npmrc', dest: '.npmrc' },
70
+ { src: 'root/.nvmrc', dest: '.nvmrc' },
71
+ { src: 'root/.editorconfig', dest: '.editorconfig' },
72
+ { src: 'root/.gitignore', dest: '.gitignore' },
73
+ { src: 'packages/common-types', dest: 'packages/common-types' },
74
+ { src: 'packages/api-client', dest: 'packages/api-client' },
75
+ ],
76
+ byPlatform: {
77
+ web: [{ src: 'apps/web', dest: 'apps/web' }],
78
+ mobile: [{ src: 'apps/mobile', dest: 'apps/mobile' }],
79
+ api: [{ src: 'apps/api', dest: 'apps/api' }],
80
+ },
81
+ byFeature: {
82
+ 'github-actions': [{ src: '.github', dest: '.github' }],
83
+ 'vscode-config': [{ src: '.vscode', dest: '.vscode' }],
84
+ },
85
+ byAuthProvider: {
86
+ cognito: [
87
+ { src: 'apps/api/cdk/auth', dest: 'apps/api/cdk/auth' },
88
+ { src: 'apps/web/src/auth/cognito-provider.tsx', dest: 'apps/web/src/auth/cognito-provider.tsx' },
89
+ { src: 'apps/web/src/config/amplify-config.ts', dest: 'apps/web/src/config/amplify-config.ts' },
90
+ { src: 'apps/api/src/middleware/cognito-auth.ts', dest: 'apps/api/src/middleware/cognito-auth.ts' },
91
+ ],
92
+ auth0: [
93
+ { src: 'apps/web/src/auth/auth0-provider.tsx', dest: 'apps/web/src/auth/auth0-provider.tsx' },
94
+ { src: 'apps/web/src/config/auth0-config.ts', dest: 'apps/web/src/config/auth0-config.ts' },
95
+ { src: 'apps/api/src/middleware/auth0-auth.ts', dest: 'apps/api/src/middleware/auth0-auth.ts' },
96
+ ],
97
+ none: [],
98
+ },
99
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Template Token Constants
3
+ *
4
+ * Placeholder tokens used throughout template files for project customization.
5
+ * Uses double-brace syntax {{TOKEN}} because:
6
+ * - Distinct from JS template literals (${}), EJS (<%%>), Mustache ({{}})
7
+ * - Easy to search/replace with simple regex
8
+ * - Visible in any file type (JSON, TS, MD)
9
+ */
10
+ export declare const TOKENS: {
11
+ /** Project name in kebab-case (e.g., my-awesome-app) */
12
+ readonly PROJECT_NAME: "{{PROJECT_NAME}}";
13
+ /** Project name in PascalCase for class names, stack names (e.g., MyAwesomeApp) */
14
+ readonly PROJECT_NAME_PASCAL: "{{PROJECT_NAME_PASCAL}}";
15
+ /** Project name in Title Case for display (e.g., My Awesome App) */
16
+ readonly PROJECT_NAME_TITLE: "{{PROJECT_NAME_TITLE}}";
17
+ /** AWS region (e.g., us-east-1) */
18
+ readonly AWS_REGION: "{{AWS_REGION}}";
19
+ /** Package scope derived from project name (e.g., @my-awesome-app) */
20
+ readonly PACKAGE_SCOPE: "{{PACKAGE_SCOPE}}";
21
+ /** Brand color for theme (e.g., blue, purple, teal, green, orange) */
22
+ readonly BRAND_COLOR: "{{BRAND_COLOR}}";
23
+ /** Organization enabled flag ('true' or 'false') */
24
+ readonly ORG_ENABLED: "{{ORG_ENABLED}}";
25
+ /** Organization name */
26
+ readonly ORG_NAME: "{{ORG_NAME}}";
27
+ /** JSON array of {environment, accountId} objects for flexible environment handling */
28
+ readonly ORG_ACCOUNTS_JSON: "{{ORG_ACCOUNTS_JSON}}";
29
+ /** Development environment AWS Account ID (empty if not selected) */
30
+ readonly DEV_ACCOUNT_ID: "{{DEV_ACCOUNT_ID}}";
31
+ /** Staging environment AWS Account ID (empty if not selected) */
32
+ readonly STAGE_ACCOUNT_ID: "{{STAGE_ACCOUNT_ID}}";
33
+ /** Production environment AWS Account ID (empty if not selected) */
34
+ readonly PROD_ACCOUNT_ID: "{{PROD_ACCOUNT_ID}}";
35
+ };
36
+ /** Regex pattern to match any {{TOKEN_NAME}} placeholder */
37
+ export declare const TOKEN_PATTERN: RegExp;
38
+ /** Type representing valid token names */
39
+ export type TokenName = keyof typeof TOKENS;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Template Token Constants
3
+ *
4
+ * Placeholder tokens used throughout template files for project customization.
5
+ * Uses double-brace syntax {{TOKEN}} because:
6
+ * - Distinct from JS template literals (${}), EJS (<%%>), Mustache ({{}})
7
+ * - Easy to search/replace with simple regex
8
+ * - Visible in any file type (JSON, TS, MD)
9
+ */
10
+ export const TOKENS = {
11
+ /** Project name in kebab-case (e.g., my-awesome-app) */
12
+ PROJECT_NAME: '{{PROJECT_NAME}}',
13
+ /** Project name in PascalCase for class names, stack names (e.g., MyAwesomeApp) */
14
+ PROJECT_NAME_PASCAL: '{{PROJECT_NAME_PASCAL}}',
15
+ /** Project name in Title Case for display (e.g., My Awesome App) */
16
+ PROJECT_NAME_TITLE: '{{PROJECT_NAME_TITLE}}',
17
+ /** AWS region (e.g., us-east-1) */
18
+ AWS_REGION: '{{AWS_REGION}}',
19
+ /** Package scope derived from project name (e.g., @my-awesome-app) */
20
+ PACKAGE_SCOPE: '{{PACKAGE_SCOPE}}',
21
+ /** Brand color for theme (e.g., blue, purple, teal, green, orange) */
22
+ BRAND_COLOR: '{{BRAND_COLOR}}',
23
+ /** Organization enabled flag ('true' or 'false') */
24
+ ORG_ENABLED: '{{ORG_ENABLED}}',
25
+ /** Organization name */
26
+ ORG_NAME: '{{ORG_NAME}}',
27
+ /** JSON array of {environment, accountId} objects for flexible environment handling */
28
+ ORG_ACCOUNTS_JSON: '{{ORG_ACCOUNTS_JSON}}',
29
+ /** Development environment AWS Account ID (empty if not selected) */
30
+ DEV_ACCOUNT_ID: '{{DEV_ACCOUNT_ID}}',
31
+ /** Staging environment AWS Account ID (empty if not selected) */
32
+ STAGE_ACCOUNT_ID: '{{STAGE_ACCOUNT_ID}}',
33
+ /** Production environment AWS Account ID (empty if not selected) */
34
+ PROD_ACCOUNT_ID: '{{PROD_ACCOUNT_ID}}',
35
+ };
36
+ /** Regex pattern to match any {{TOKEN_NAME}} placeholder */
37
+ export const TOKEN_PATTERN = /\{\{([A-Z_]+)\}\}/g;
@@ -0,0 +1,52 @@
1
+ import type { ProjectConfig, Feature, AuthProvider } from '../types.js';
2
+ /** Mapping of token names to their replacement values */
3
+ export interface TokenValues {
4
+ PROJECT_NAME: string;
5
+ PROJECT_NAME_PASCAL: string;
6
+ PROJECT_NAME_TITLE: string;
7
+ AWS_REGION: string;
8
+ PACKAGE_SCOPE: string;
9
+ BRAND_COLOR: string;
10
+ AUTH_COGNITO: string;
11
+ AUTH_AUTH0: string;
12
+ AUTH_SOCIAL_LOGIN: string;
13
+ AUTH_MFA: string;
14
+ /** Organization enabled flag ('true' or 'false') */
15
+ ORG_ENABLED?: string;
16
+ /** Organization name */
17
+ ORG_NAME?: string;
18
+ /** JSON array of {environment, accountId} objects for templates needing full list */
19
+ ORG_ACCOUNTS_JSON?: string;
20
+ /** Development environment AWS Account ID (empty if not selected) */
21
+ DEV_ACCOUNT_ID?: string;
22
+ /** Staging environment AWS Account ID (empty if not selected) */
23
+ STAGE_ACCOUNT_ID?: string;
24
+ /** Production environment AWS Account ID (empty if not selected) */
25
+ PROD_ACCOUNT_ID?: string;
26
+ }
27
+ /** Platform identifiers for conditional templates */
28
+ export type Platform = 'web' | 'mobile' | 'api';
29
+ /** A single template file entry */
30
+ export interface TemplateFile {
31
+ /** Source path relative to templates/ directory */
32
+ src: string;
33
+ /** Destination path relative to output directory (may contain tokens) */
34
+ dest: string;
35
+ /** Which platforms this file belongs to (undefined = all platforms) */
36
+ platforms?: Platform[];
37
+ }
38
+ /** Complete template manifest */
39
+ export interface TemplateManifest {
40
+ /** Files that are always included */
41
+ shared: TemplateFile[];
42
+ /** Files grouped by platform */
43
+ byPlatform: Record<Platform, TemplateFile[]>;
44
+ /** Files grouped by feature */
45
+ byFeature: Record<Feature, TemplateFile[]>;
46
+ /** Files grouped by auth provider */
47
+ byAuthProvider: Record<AuthProvider, TemplateFile[]>;
48
+ }
49
+ /** Function to derive token values from ProjectConfig */
50
+ export type DeriveTokenValues = (config: ProjectConfig) => TokenValues;
51
+ /** Re-export Feature and AuthProvider types for convenience */
52
+ export type { Feature, AuthProvider };
@@ -0,0 +1 @@
1
+ export {};