nebula-starter-kit 0.0.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 (81) hide show
  1. package/README.md +107 -0
  2. package/dist/index.js +8 -0
  3. package/dist/run.js +112 -0
  4. package/dist/utils/addService.js +204 -0
  5. package/dist/utils/appName.js +75 -0
  6. package/dist/utils/deployNow.js +18 -0
  7. package/dist/utils/generateFiles.js +326 -0
  8. package/dist/utils/generateSchemas.js +58 -0
  9. package/dist/utils/listServices.js +24 -0
  10. package/dist/utils/replaceServiceNames.js +42 -0
  11. package/dist/utils/telemetryAddon.js +91 -0
  12. package/package.json +31 -0
  13. package/templates/core/audit/audit.controller.ts +125 -0
  14. package/templates/core/audit/audit.module.ts +10 -0
  15. package/templates/core/audit/audit.schema.ts +14 -0
  16. package/templates/core/audit/audit.service.ts +47 -0
  17. package/templates/core/auth/auth.controller.ts +207 -0
  18. package/templates/core/auth/auth.dto.ts +50 -0
  19. package/templates/core/auth/auth.module.ts +10 -0
  20. package/templates/core/auth/auth.service.ts +178 -0
  21. package/templates/core/auth/utils.ts +160 -0
  22. package/templates/core/constants/environment.db.ts +27 -0
  23. package/templates/core/constants/environment.module.ts +9 -0
  24. package/templates/core/constants/environment.service.ts +69 -0
  25. package/templates/core/core.controller.ts +35 -0
  26. package/templates/core/core.module.ts +22 -0
  27. package/templates/core/database/database.module.ts +20 -0
  28. package/templates/core/database/database.provider.ts +32 -0
  29. package/templates/core/database/database.service.ts +168 -0
  30. package/templates/core/database/database.types.ts +13 -0
  31. package/templates/core/filters/audit.decorator.ts +5 -0
  32. package/templates/core/filters/audit.interceptor.ts +74 -0
  33. package/templates/core/filters/http-exception.filter.ts +43 -0
  34. package/templates/core/filters/success-message.decorator.ts +5 -0
  35. package/templates/core/filters/success-response.interceptor.ts +35 -0
  36. package/templates/core/summarize/summarize.controller.ts +74 -0
  37. package/templates/core/summarize/summarize.dto.ts +13 -0
  38. package/templates/core/summarize/summarize.module.ts +9 -0
  39. package/templates/core/summarize/summarize.service.ts +54 -0
  40. package/templates/nest-cli.json +8 -0
  41. package/templates/package.json +52 -0
  42. package/templates/service/src/__name__.controller.ts +15 -0
  43. package/templates/service/src/__name__.module.ts +11 -0
  44. package/templates/service/src/__name__.schema.ts +15 -0
  45. package/templates/service/src/__name__.service.ts +12 -0
  46. package/templates/service/src/lambda.ts +60 -0
  47. package/templates/tsconfig.json +28 -0
  48. package/templates/ui/README.md +36 -0
  49. package/templates/ui/eslint.config.mjs +18 -0
  50. package/templates/ui/next.config.ts +8 -0
  51. package/templates/ui/package.json +33 -0
  52. package/templates/ui/postcss.config.mjs +7 -0
  53. package/templates/ui/public/file.svg +1 -0
  54. package/templates/ui/public/globe.svg +1 -0
  55. package/templates/ui/public/next.svg +1 -0
  56. package/templates/ui/public/vercel.svg +1 -0
  57. package/templates/ui/public/window.svg +1 -0
  58. package/templates/ui/src/app/LandingPage.tsx +98 -0
  59. package/templates/ui/src/app/ai/summarize/page.tsx +115 -0
  60. package/templates/ui/src/app/context/AuthContext.tsx +48 -0
  61. package/templates/ui/src/app/favicon.ico +0 -0
  62. package/templates/ui/src/app/globals.css +26 -0
  63. package/templates/ui/src/app/layout.tsx +37 -0
  64. package/templates/ui/src/app/page.tsx +7 -0
  65. package/templates/ui/src/app/services/page.tsx +99 -0
  66. package/templates/ui/src/components/Auth.css +252 -0
  67. package/templates/ui/src/components/Auth.tsx +455 -0
  68. package/templates/ui/src/components/Error.tsx +32 -0
  69. package/templates/ui/src/components/FormInput.tsx +77 -0
  70. package/templates/ui/src/components/Loading.tsx +10 -0
  71. package/templates/ui/src/components/Login.tsx +171 -0
  72. package/templates/ui/src/components/Popup.css +90 -0
  73. package/templates/ui/src/components/Signup.tsx +155 -0
  74. package/templates/ui/src/utils/axiosInstance.ts +37 -0
  75. package/templates/ui/src/utils/axiosRawInstance.ts +33 -0
  76. package/templates/ui/src/utils/util.constant.ts +0 -0
  77. package/templates/ui/src/utils/util.function.ts +165 -0
  78. package/templates/ui/src/utils/util.type.ts +64 -0
  79. package/templates/ui/src/utils/variables.ts +6 -0
  80. package/templates/ui/tailwind.config.js +8 -0
  81. package/templates/ui/tsconfig.json +43 -0
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # Nebula Logix Starter Kit
2
+
3
+ This is a downloadable & installable AWS production-ready AI-enabled package that serves essentially as a Software As A Service (SaaS), that users/clients can setup quickly in their AWS environment.
4
+
5
+ ## Components
6
+ - cli/ directory to generate a full-fledged deployable application with a variety of modules and functionalities to choose from.
7
+ - templates/ directory containing the base NestJS application template.
8
+ - modules/ directory for the modules options.
9
+
10
+ ## Features
11
+ - NestJS framework for building scalable and maintainable server-side applications.
12
+ - AWS Lambda integration for serverless deployment.
13
+ - Pre-configured TypeScript support.
14
+ - Sample API endpoint to demonstrate functionality.
15
+
16
+ ## Prerequisites
17
+ - Node.js (version 14 or higher)
18
+ - npm (version 6 or higher)
19
+ - AWS CLI configured with your credentials
20
+
21
+ ## Setup
22
+
23
+ ```bash
24
+ Navigate to the 'cli' directory
25
+
26
+ $ RUN cd cli
27
+ $ RUN npm install
28
+ $ RUN nebula create <app-name>
29
+ ```
30
+
31
+ ## Deployment
32
+
33
+ ```bash
34
+ Navigate to the app directory
35
+
36
+ $ RUN cd <app-name>
37
+ $ RUN serverless deploy --config infra/api/serverless.yml
38
+ $ COPY the "ServiceEndpoint" value from the terminal output and update the NEXT_PUBLIC_API_URL of the .env.local of the ui directory
39
+ $ RUN npm run deploy
40
+
41
+ $ Navigate to the "WebsiteURL" of the buckets on the terminal output
42
+ ```
43
+
44
+ ## Teardown
45
+
46
+ ```bash
47
+ Navigate to the app directory
48
+
49
+ $ RUN cd <app-name>
50
+ $ RUN npm run teardown
51
+ ```
52
+
53
+ ## Common Errors
54
+
55
+ ```
56
+ ❌ Not a nebula project
57
+ Usage: Run nebula command only in specified locations
58
+ ```
59
+
60
+ ```
61
+ ❌ Unknown command
62
+ Available commands
63
+ 1. nebula create <app-name>
64
+ 2. nebula add service <service-name>
65
+ 3. nebula list services
66
+ ```
67
+
68
+ ```
69
+ ❌ Services directory not found
70
+ ```
71
+
72
+ ```
73
+ ❌ Modules directory not found
74
+ ```
75
+
76
+ ```
77
+ Example of the folder structure of the starter kit and an nlx app generated.
78
+ The ui directory contains the NextJS React App
79
+
80
+ The infra contains the api gateway, s3 buckets and other associated infrastructure setup.
81
+
82
+ The services contains the individual service modules as determined by the user.
83
+
84
+ The core has the database, authentication and other related features.
85
+ ```
86
+
87
+ ```
88
+ ├── cli
89
+ │ ├── dist
90
+ │ ├── nebula.json
91
+ │ ├── package-lock.json
92
+ │ ├── package.json
93
+ │ ├── src
94
+ │ ├── templates
95
+ │ └── tsconfig.json
96
+ ├── nlx
97
+ │ ├── core
98
+ │ ├── infra
99
+ │ ├── nebula.json
100
+ │ ├── package.json
101
+ │ ├── serverless-compose.yml
102
+ │ ├── services
103
+ │ ├── tsconfig.json
104
+ │ └── ui
105
+ └── README.md
106
+
107
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const run_1 = require("./run");
5
+ (0, run_1.run)().catch((err) => {
6
+ console.error(err.message);
7
+ process.exit(1);
8
+ });
package/dist/run.js ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.run = run;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const child_process_1 = require("child_process");
12
+ const appName_1 = require("./utils/appName");
13
+ const deployNow_1 = require("./utils/deployNow");
14
+ const telemetryAddon_1 = require("./utils/telemetryAddon");
15
+ const generateFiles_1 = require("./utils/generateFiles");
16
+ const generateSchemas_1 = require("./utils/generateSchemas");
17
+ const ROOT = process.cwd();
18
+ const region = (0, telemetryAddon_1.getAwsRegion)();
19
+ console.log('\nregion', region, '\n');
20
+ let appNamePlaceHolder;
21
+ async function run() {
22
+ const appName = await (0, appName_1.promptAppName)();
23
+ appNamePlaceHolder = appName;
24
+ console.log('appNamePlaceHolder', appNamePlaceHolder);
25
+ const OUTPUT = path_1.default.join(ROOT, `../${appName}`);
26
+ if (await fs_extra_1.default.pathExists(OUTPUT)) {
27
+ console.log(`🧹 Cleaning ${appName} folder...\n`);
28
+ await fs_extra_1.default.remove(OUTPUT);
29
+ }
30
+ await fs_extra_1.default.ensureDir(OUTPUT);
31
+ console.log(`📁 Fresh ${appName} created\n`);
32
+ const { selectionMode } = await inquirer_1.default.prompt([
33
+ {
34
+ type: 'list',
35
+ name: 'selectionMode',
36
+ message: 'How would you like to define services?',
37
+ choices: ['Select from available modules', 'Type service names manually'],
38
+ },
39
+ ]);
40
+ let selectedServices = [];
41
+ const modulesDir = path_1.default.join(ROOT, './templates/modules');
42
+ if (!fs_extra_1.default.existsSync(modulesDir)) {
43
+ console.log(`❌ Modules directory not found\n`);
44
+ throw new Error('Modules directory not found');
45
+ // process.exit(1);
46
+ }
47
+ if (selectionMode === 'Select from available modules') {
48
+ const { services } = await inquirer_1.default.prompt([
49
+ {
50
+ type: 'checkbox',
51
+ name: 'services',
52
+ message: 'Select services',
53
+ choices: fs_extra_1.default.readdirSync(path_1.default.join(ROOT, './templates/modules')),
54
+ },
55
+ ]);
56
+ selectedServices = services;
57
+ }
58
+ if (selectionMode === 'Type service names manually') {
59
+ // TODO Validate service names for casing and other formats
60
+ const { servicesInput } = await inquirer_1.default.prompt([
61
+ {
62
+ type: 'input',
63
+ name: 'servicesInput',
64
+ message: 'Enter service names (comma separated, e.g. products,orders,users):',
65
+ },
66
+ ]);
67
+ const services = servicesInput
68
+ .split(',')
69
+ .map((s) => s.trim())
70
+ .filter(Boolean);
71
+ selectedServices = services;
72
+ }
73
+ // Move core module into app
74
+ const coreDir = path_1.default.join(OUTPUT, 'core');
75
+ await fs_extra_1.default.ensureDir(coreDir);
76
+ fs_extra_1.default.copySync(path_1.default.join(ROOT, 'templates/core'), coreDir);
77
+ // Move UI module into app
78
+ const uiDir = path_1.default.join(OUTPUT, 'ui');
79
+ await fs_extra_1.default.ensureDir(uiDir);
80
+ fs_extra_1.default.copySync(path_1.default.join(ROOT, 'templates/ui'), uiDir);
81
+ // Generate nebula json
82
+ (0, generateFiles_1.generateNebulaJson)(appName, selectedServices, OUTPUT);
83
+ (0, generateSchemas_1.generateSchemas)(OUTPUT);
84
+ // Generate root lambda
85
+ (0, generateFiles_1.generateRootLambda)(appName, selectedServices, OUTPUT);
86
+ // Generate serverless.yml for infra/api gateway
87
+ await (0, generateFiles_1.generateInfraApiFile)(appName, OUTPUT);
88
+ // Generate serverless.yml for infra/buckets
89
+ await (0, generateFiles_1.generateInfraBucketFile)(appName, OUTPUT);
90
+ // Generate serverless.yml for infra/cognito
91
+ await (0, generateFiles_1.generateInfraCognitoFile)(appName, OUTPUT);
92
+ // Move package.json into app
93
+ await fs_extra_1.default.copy(path_1.default.join(ROOT, 'templates/package.json'), path_1.default.join(OUTPUT, 'package.json'));
94
+ // Move tsconfig into app
95
+ await fs_extra_1.default.copy(path_1.default.join(ROOT, 'templates/tsconfig.json'), path_1.default.join(OUTPUT, 'tsconfig.json'));
96
+ // Handle content for services
97
+ await (0, generateFiles_1.generateServerlessFiles)(selectedServices, ROOT, OUTPUT, appNamePlaceHolder);
98
+ // Create env file for Root environment variables
99
+ (0, generateFiles_1.generateRootEnv)(OUTPUT);
100
+ // Create env file for NextJS environment variables
101
+ (0, generateFiles_1.generateNextJSEnv)(appName, uiDir, selectedServices);
102
+ // Prompt telemetry
103
+ await (0, telemetryAddon_1.promptTelemetry)(appName, selectedServices);
104
+ // 7. Install deps & deploy
105
+ const deployNow = await (0, deployNow_1.promptDeployNow)();
106
+ if (deployNow) {
107
+ (0, child_process_1.execSync)('npm install && npm run deploy', {
108
+ cwd: OUTPUT,
109
+ stdio: 'inherit',
110
+ });
111
+ }
112
+ }
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.serverlessTemplate = void 0;
7
+ exports.addService = addService;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const replaceServiceNames_1 = require("./replaceServiceNames");
11
+ const telemetryAddon_1 = require("./telemetryAddon");
12
+ const yaml_1 = __importDefault(require("yaml"));
13
+ const generateFiles_1 = require("./generateFiles");
14
+ const generateSchemas_1 = require("./generateSchemas");
15
+ const region = (0, telemetryAddon_1.getAwsRegion)();
16
+ function getServicePorts(service, appName) {
17
+ const ROOT = process.cwd();
18
+ let config;
19
+ let nebulaPath;
20
+ let httpPort = 3001;
21
+ let lambdaPort = 3001;
22
+ if (!appName) {
23
+ nebulaPath = path_1.default.join(ROOT, 'nebula.json');
24
+ if (!fs_extra_1.default.existsSync(nebulaPath)) {
25
+ throw new Error('Not a Nebula project');
26
+ }
27
+ config = fs_extra_1.default.readJsonSync(nebulaPath);
28
+ appName = config.name;
29
+ const servicesCount = config.services.length;
30
+ httpPort = 3001 + servicesCount * 2;
31
+ lambdaPort = httpPort + 1;
32
+ }
33
+ else {
34
+ nebulaPath = path_1.default.join(ROOT, `../${appName}`, 'nebula.json');
35
+ if (!fs_extra_1.default.existsSync(nebulaPath)) {
36
+ throw new Error('Not a Nebula project');
37
+ }
38
+ config = fs_extra_1.default.readJsonSync(nebulaPath);
39
+ const index = config.services.indexOf(service);
40
+ httpPort = 3001 + index * 2;
41
+ lambdaPort = httpPort + 1;
42
+ }
43
+ return { httpPort, lambdaPort, appName };
44
+ }
45
+ const serverlessTemplate = (service, appName) => {
46
+ const { httpPort, lambdaPort, appName: nameTag, } = getServicePorts(service, appName);
47
+ console.log('offline port values for service:', service, httpPort, lambdaPort, nameTag);
48
+ return `service: ${nameTag}-${service}
49
+
50
+ provider:
51
+ name: aws
52
+ runtime: nodejs20.x
53
+ region: ${region}
54
+ stage: \${opt:stage, 'dev'}
55
+ memorySize: 256
56
+ timeout: 30
57
+
58
+ environment:
59
+ REGION: us-east-1
60
+ COGNITO_CLIENT_ID: \${param:CognitoClientId, env:COGNITO_CLIENT_ID}
61
+ COGNITO_USER_POOL_ID: \${param:CognitoUserPoolId, env:COGNITO_USER_POOL_ID}
62
+
63
+ apiGateway:
64
+ restApiId: \${param:ApiGatewayRestApiId, null}
65
+ restApiRootResourceId: \${param:ApiGatewayRootResourceId, null}
66
+
67
+ stackTags:
68
+ CostCenter: \${self:provider.stage}-\${aws:accountId}
69
+
70
+ iam:
71
+ role:
72
+ statements:
73
+ # ✅ Bedrock permission
74
+ - Effect: Allow
75
+ Action:
76
+ - bedrock:InvokeModel
77
+ Resource:
78
+ - arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-haiku-20240307-v1:0
79
+
80
+ # ✅ Cognito permission
81
+ - Effect: Allow
82
+ Action:
83
+ - cognito-idp:ListUsers
84
+ Resource:
85
+ - arn:aws:cognito-idp:\${self:provider.region}:\${aws:accountId}:userpool/\${param:CognitoUserPoolId, env:COGNITO_USER_POOL_ID}
86
+
87
+ # ✅ DynamoDB permission
88
+ - Effect: Allow
89
+ Action:
90
+ - dynamodb:DescribeTable
91
+ - dynamodb:CreateTable
92
+ - dynamodb:GetItem
93
+ - dynamodb:PutItem
94
+ - dynamodb:UpdateItem
95
+ - dynamodb:Query
96
+ - dynamodb:Scan
97
+ Resource:
98
+ - arn:aws:dynamodb:\${self:provider.region}:*:table/*
99
+
100
+ # ✅ Cloudformation permission
101
+ - Effect: Allow
102
+ Action:
103
+ - cloudformation:ListStacks
104
+ - cloudformation:DescribeStacks
105
+ Resource: "*"
106
+
107
+ custom:
108
+ serverless-offline:
109
+ noPrependStageInUrl: true
110
+ httpPort: ${httpPort}
111
+ lambdaPort: ${lambdaPort}
112
+
113
+ build:
114
+ esbuild:
115
+ bundle: true
116
+ minify: false
117
+ sourcemap: true
118
+ keepNames: true
119
+ target: node20
120
+ format: cjs
121
+
122
+ external:
123
+ - aws-sdk
124
+ - "@nestjs/microservices"
125
+ - "@nestjs/microservices/microservices-module"
126
+ - "@nestjs/websockets"
127
+ - "@nestjs/websockets/socket-module"
128
+ - "class-transformer/storage"
129
+
130
+ functions:
131
+ app:
132
+ handler: src/lambda.handler
133
+ events:
134
+ - http:
135
+ path: /${service}/{proxy+}
136
+ method: any
137
+ cors: true
138
+
139
+ package:
140
+ individually: true
141
+
142
+ plugins:
143
+ - serverless-offline
144
+ `;
145
+ };
146
+ exports.serverlessTemplate = serverlessTemplate;
147
+ async function addService(serviceName, selectedServices, appName) {
148
+ const ROOT = process.cwd();
149
+ const nebulaPath = path_1.default.join(ROOT, 'nebula.json');
150
+ if (!fs_extra_1.default.existsSync(nebulaPath)) {
151
+ throw new Error('Not a Nebula project');
152
+ }
153
+ const config = fs_extra_1.default.readJsonSync(nebulaPath);
154
+ if (config.services.includes(serviceName)) {
155
+ console.log('Service already exists');
156
+ return;
157
+ }
158
+ // create folder
159
+ const serviceDir = path_1.default.join(ROOT, 'services', serviceName);
160
+ await fs_extra_1.default.ensureDir(serviceDir);
161
+ // copy base nest template
162
+ fs_extra_1.default.copySync(path_1.default.join(ROOT, '../cli/templates/service'), serviceDir);
163
+ // update service names
164
+ await (0, replaceServiceNames_1.replaceServiceNames)(serviceDir, serviceName, appName);
165
+ // Generate serverless.yml per service
166
+ await fs_extra_1.default.writeFile(path_1.default.join(serviceDir, 'serverless.yml'), (0, exports.serverlessTemplate)(serviceName));
167
+ // Regenerate root lambda
168
+ (0, generateFiles_1.generateRootLambda)(config.name, [...selectedServices, serviceName], ROOT);
169
+ // Generate root serverless-compose.yml
170
+ const composePath = path_1.default.join(ROOT, 'serverless-compose.yml');
171
+ let parsed;
172
+ if (fs_extra_1.default.existsSync(composePath)) {
173
+ parsed = yaml_1.default.parse(await fs_extra_1.default.readFile(composePath, 'utf8'));
174
+ }
175
+ else {
176
+ parsed = {
177
+ services: {
178
+ api: { path: 'infra/api' },
179
+ cognito: { path: 'infra/cognito' },
180
+ buckets: { path: 'infra/buckets' },
181
+ },
182
+ };
183
+ }
184
+ selectedServices.push(serviceName);
185
+ for (const service of selectedServices) {
186
+ if (!parsed.services[service]) {
187
+ parsed.services[service] = {
188
+ path: `services/${service}`,
189
+ params: {
190
+ ApiGatewayRestApiId: '${api.ApiGatewayRestApiId}',
191
+ ApiGatewayRootResourceId: '${api.ApiGatewayRootResourceId}',
192
+ CognitoClientId: '${cognito.CognitoClientId}',
193
+ CognitoUserPoolId: '${cognito.CognitoUserPoolId}',
194
+ },
195
+ };
196
+ }
197
+ }
198
+ await fs_extra_1.default.writeFile(composePath, yaml_1.default.stringify(parsed));
199
+ // update config
200
+ config.services.push(serviceName);
201
+ fs_extra_1.default.writeJsonSync(nebulaPath, config, { spaces: 2 });
202
+ (0, generateSchemas_1.generateSchemas)(ROOT);
203
+ console.log(`✅ Service ${serviceName} created & added`);
204
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.promptAppName = promptAppName;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const listServices_1 = require("./listServices");
11
+ const addService_1 = require("./addService");
12
+ async function promptAppName() {
13
+ const [, , command, argAppName] = process.argv;
14
+ const commands = ['create', 'add', 'list'];
15
+ const addListCommands = ['add', 'list'];
16
+ const nebulaConfig = path_1.default.join(process.cwd(), 'nebula.json');
17
+ if (!fs_extra_1.default.existsSync(nebulaConfig)) {
18
+ console.log(`❌ Not a nebula project\nUsage: Run nebula command only in specified locations\n`);
19
+ process.exit(1);
20
+ }
21
+ const config = fs_extra_1.default.readJsonSync(nebulaConfig);
22
+ if (!commands.includes(command)) {
23
+ console.log(`❌ Unknown command\nAvailable commands\n1. nebula create <app-name>\n2. nebula add service <service-name>\n3. nebula list services\n`);
24
+ process.exit(1);
25
+ }
26
+ if (addListCommands.includes(command)) {
27
+ if (!config.services) {
28
+ console.log('❌ Services directory not found\n');
29
+ process.exit(1);
30
+ }
31
+ else {
32
+ switch (command) {
33
+ case 'add':
34
+ if (!process.argv[4]) {
35
+ console.log(`❌ Missing service name\nUsage: nebula add service <service-name>\n`);
36
+ process.exit(1);
37
+ }
38
+ if (argAppName === 'service')
39
+ await (0, addService_1.addService)(process.argv[4], config.services, `${config.name}`);
40
+ process.exit(1);
41
+ case 'list':
42
+ if (argAppName !== 'services') {
43
+ console.log(`❌ Incorrect CLI command\nUsage: nebula list services\n`);
44
+ process.exit(1);
45
+ }
46
+ if (argAppName === 'services')
47
+ (0, listServices_1.listServices)();
48
+ process.exit(1);
49
+ }
50
+ }
51
+ }
52
+ if (!config.services) {
53
+ if (config.name !== 'cli') {
54
+ console.log(`❌ Incorrect CLI directory\n`);
55
+ process.exit(1);
56
+ }
57
+ }
58
+ let appName = argAppName;
59
+ // If app name not provided → prompt
60
+ if (!appName) {
61
+ const { appName: promptedName } = await inquirer_1.default.prompt([
62
+ {
63
+ type: 'input',
64
+ name: 'appName',
65
+ message: 'Enter application name:',
66
+ default: 'my-starterkit-app',
67
+ validate: (input) => /^[a-z0-9-]+$/.test(input)
68
+ ? true
69
+ : 'Use lowercase letters, numbers, and hyphens only',
70
+ },
71
+ ]);
72
+ return promptedName;
73
+ }
74
+ return appName;
75
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.promptDeployNow = promptDeployNow;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ async function promptDeployNow() {
9
+ const { deployNow } = await inquirer_1.default.prompt([
10
+ {
11
+ type: 'confirm',
12
+ name: 'deployNow',
13
+ message: 'Deploy to AWS using SAM now?',
14
+ default: false,
15
+ },
16
+ ]);
17
+ return deployNow;
18
+ }