spense-core 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.
@@ -0,0 +1,16 @@
1
+ import { AwsCredentials } from './types';
2
+ export interface ExistingInstance {
3
+ id: string;
4
+ name: string;
5
+ type: string;
6
+ state: string;
7
+ publicIp?: string;
8
+ }
9
+ export interface ExistingDatabase {
10
+ id: string;
11
+ engine: string;
12
+ instanceClass: string;
13
+ endpoint?: string;
14
+ }
15
+ export declare function listEc2Instances(creds: AwsCredentials): Promise<ExistingInstance[]>;
16
+ export declare function listRdsInstances(creds: AwsCredentials): Promise<ExistingDatabase[]>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listEc2Instances = listEc2Instances;
4
+ exports.listRdsInstances = listRdsInstances;
5
+ const client_ec2_1 = require("@aws-sdk/client-ec2");
6
+ const client_rds_1 = require("@aws-sdk/client-rds");
7
+ async function listEc2Instances(creds) {
8
+ const ec2 = new client_ec2_1.EC2Client({
9
+ region: creds.region,
10
+ credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey }
11
+ });
12
+ const res = await ec2.send(new client_ec2_1.DescribeInstancesCommand({}));
13
+ const instances = [];
14
+ for (const reservation of res.Reservations || []) {
15
+ for (const inst of reservation.Instances || []) {
16
+ if (inst.State?.Name === 'terminated')
17
+ continue;
18
+ instances.push({
19
+ id: inst.InstanceId || '',
20
+ name: inst.Tags?.find(t => t.Key === 'Name')?.Value || 'Unnamed',
21
+ type: inst.InstanceType || '',
22
+ state: inst.State?.Name || '',
23
+ publicIp: inst.PublicIpAddress,
24
+ });
25
+ }
26
+ }
27
+ return instances;
28
+ }
29
+ async function listRdsInstances(creds) {
30
+ const rds = new client_rds_1.RDSClient({
31
+ region: creds.region,
32
+ credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey }
33
+ });
34
+ const res = await rds.send(new client_rds_1.DescribeDBInstancesCommand({}));
35
+ return (res.DBInstances || []).map(db => ({
36
+ id: db.DBInstanceIdentifier || '',
37
+ engine: db.Engine || '',
38
+ instanceClass: db.DBInstanceClass || '',
39
+ endpoint: db.Endpoint?.Address,
40
+ }));
41
+ }
@@ -0,0 +1,12 @@
1
+ import { AwsCredentials } from './types';
2
+ export interface PermissionCheck {
3
+ service: string;
4
+ hasAccess: boolean;
5
+ error?: string;
6
+ }
7
+ export declare function validateCredentials(creds: AwsCredentials): Promise<{
8
+ valid: boolean;
9
+ username?: string;
10
+ error?: string;
11
+ }>;
12
+ export declare function checkPermissions(creds: AwsCredentials): Promise<PermissionCheck[]>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateCredentials = validateCredentials;
4
+ exports.checkPermissions = checkPermissions;
5
+ const client_ec2_1 = require("@aws-sdk/client-ec2");
6
+ const client_rds_1 = require("@aws-sdk/client-rds");
7
+ const client_elastic_load_balancing_v2_1 = require("@aws-sdk/client-elastic-load-balancing-v2");
8
+ const client_route_53_1 = require("@aws-sdk/client-route-53");
9
+ const client_auto_scaling_1 = require("@aws-sdk/client-auto-scaling");
10
+ const client_iam_1 = require("@aws-sdk/client-iam");
11
+ async function validateCredentials(creds) {
12
+ const iam = new client_iam_1.IAMClient({
13
+ region: creds.region,
14
+ credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey }
15
+ });
16
+ try {
17
+ const res = await iam.send(new client_iam_1.GetUserCommand({}));
18
+ return { valid: true, username: res.User?.UserName };
19
+ }
20
+ catch (err) {
21
+ return { valid: false, error: err.message };
22
+ }
23
+ }
24
+ async function checkPermissions(creds) {
25
+ const config = {
26
+ region: creds.region,
27
+ credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey }
28
+ };
29
+ const checks = [];
30
+ // EC2
31
+ try {
32
+ const ec2 = new client_ec2_1.EC2Client(config);
33
+ await ec2.send(new client_ec2_1.DescribeInstancesCommand({ MaxResults: 5 }));
34
+ checks.push({ service: 'EC2', hasAccess: true });
35
+ }
36
+ catch (err) {
37
+ checks.push({ service: 'EC2', hasAccess: false, error: err.message });
38
+ }
39
+ // RDS
40
+ try {
41
+ const rds = new client_rds_1.RDSClient(config);
42
+ await rds.send(new client_rds_1.DescribeDBInstancesCommand({}));
43
+ checks.push({ service: 'RDS', hasAccess: true });
44
+ }
45
+ catch (err) {
46
+ checks.push({ service: 'RDS', hasAccess: false, error: err.message });
47
+ }
48
+ // ALB
49
+ try {
50
+ const elb = new client_elastic_load_balancing_v2_1.ElasticLoadBalancingV2Client(config);
51
+ await elb.send(new client_elastic_load_balancing_v2_1.DescribeLoadBalancersCommand({}));
52
+ checks.push({ service: 'ALB', hasAccess: true });
53
+ }
54
+ catch (err) {
55
+ checks.push({ service: 'ALB', hasAccess: false, error: err.message });
56
+ }
57
+ // Route53
58
+ try {
59
+ const r53 = new client_route_53_1.Route53Client(config);
60
+ await r53.send(new client_route_53_1.ListHostedZonesCommand({}));
61
+ checks.push({ service: 'Route53', hasAccess: true });
62
+ }
63
+ catch (err) {
64
+ checks.push({ service: 'Route53', hasAccess: false, error: err.message });
65
+ }
66
+ // Auto Scaling
67
+ try {
68
+ const asg = new client_auto_scaling_1.AutoScalingClient(config);
69
+ await asg.send(new client_auto_scaling_1.DescribeAutoScalingGroupsCommand({ MaxRecords: 1 }));
70
+ checks.push({ service: 'AutoScaling', hasAccess: true });
71
+ }
72
+ catch (err) {
73
+ checks.push({ service: 'AutoScaling', hasAccess: false, error: err.message });
74
+ }
75
+ return checks;
76
+ }
@@ -0,0 +1,2 @@
1
+ import { DeployConfig, ProjectInfo } from './types';
2
+ export declare function runConversation(project: ProjectInfo): Promise<DeployConfig>;
@@ -0,0 +1,293 @@
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.runConversation = runConversation;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const types_1 = require("./types");
10
+ const aws_validator_1 = require("./aws-validator");
11
+ const aws_resources_1 = require("./aws-resources");
12
+ async function runConversation(project) {
13
+ console.log(chalk_1.default.blue('\nšŸš€ Spense - Let\'s deploy your app!\n'));
14
+ console.log(chalk_1.default.gray(`Detected: ${project.type} project "${project.name}"\n`));
15
+ // Step 1: AWS Credentials
16
+ const credentials = await askCredentials();
17
+ // Step 2: Validate & check permissions
18
+ await validateAndCheckPermissions(credentials);
19
+ // Step 3: EC2 configuration
20
+ const ec2 = await askEc2Config(credentials);
21
+ // Step 4: Elastic IP
22
+ const useElasticIp = await askElasticIp(ec2);
23
+ // Step 5: Database
24
+ const { database, dbInstanceClass } = await askDatabase(credentials);
25
+ // Step 6: Domain & HTTPS
26
+ const { domain, useHttps } = await askDomain();
27
+ // Step 7: Summary & confirm
28
+ const config = {
29
+ credentials,
30
+ ec2,
31
+ useElasticIp,
32
+ database,
33
+ dbInstanceClass,
34
+ domain,
35
+ useHttps,
36
+ };
37
+ await showSummary(config);
38
+ return config;
39
+ }
40
+ async function askCredentials() {
41
+ console.log(chalk_1.default.yellow('Step 1: AWS Credentials\n'));
42
+ console.log(chalk_1.default.gray('We need AWS credentials to deploy your app. These are stored locally and never sent anywhere.\n'));
43
+ const answers = await inquirer_1.default.prompt([
44
+ {
45
+ type: 'password',
46
+ name: 'accessKeyId',
47
+ message: 'AWS Access Key ID:',
48
+ mask: '*',
49
+ validate: (v) => v.length === 20 || 'Access Key ID should be 20 characters'
50
+ },
51
+ {
52
+ type: 'password',
53
+ name: 'secretAccessKey',
54
+ message: 'AWS Secret Access Key:',
55
+ mask: '*',
56
+ validate: (v) => v.length === 40 || 'Secret Access Key should be 40 characters'
57
+ },
58
+ {
59
+ type: 'list',
60
+ name: 'region',
61
+ message: 'AWS Region:',
62
+ choices: [
63
+ { name: 'US East (N. Virginia) - us-east-1', value: 'us-east-1' },
64
+ { name: 'US West (Oregon) - us-west-2', value: 'us-west-2' },
65
+ { name: 'EU (Ireland) - eu-west-1', value: 'eu-west-1' },
66
+ { name: 'Asia Pacific (Singapore) - ap-southeast-1', value: 'ap-southeast-1' },
67
+ { name: 'Asia Pacific (Sydney) - ap-southeast-2', value: 'ap-southeast-2' },
68
+ ]
69
+ }
70
+ ]);
71
+ return answers;
72
+ }
73
+ async function validateAndCheckPermissions(creds) {
74
+ console.log(chalk_1.default.yellow('\nStep 2: Validating credentials...\n'));
75
+ const validation = await (0, aws_validator_1.validateCredentials)(creds);
76
+ if (!validation.valid) {
77
+ console.log(chalk_1.default.red(`āœ— Invalid credentials: ${validation.error}`));
78
+ process.exit(1);
79
+ }
80
+ console.log(chalk_1.default.green(`āœ“ Authenticated as: ${validation.username}\n`));
81
+ console.log(chalk_1.default.gray('Checking permissions for required services...\n'));
82
+ const permissions = await (0, aws_validator_1.checkPermissions)(creds);
83
+ let allGood = true;
84
+ for (const p of permissions) {
85
+ if (p.hasAccess) {
86
+ console.log(chalk_1.default.green(` āœ“ ${p.service}`));
87
+ }
88
+ else {
89
+ console.log(chalk_1.default.red(` āœ— ${p.service}: ${p.error}`));
90
+ allGood = false;
91
+ }
92
+ }
93
+ if (!allGood) {
94
+ console.log(chalk_1.default.red('\n⚠ Some permissions are missing. Deployment may fail.'));
95
+ const { proceed } = await inquirer_1.default.prompt([{
96
+ type: 'confirm',
97
+ name: 'proceed',
98
+ message: 'Continue anyway?',
99
+ default: false
100
+ }]);
101
+ if (!proceed)
102
+ process.exit(1);
103
+ }
104
+ console.log('');
105
+ }
106
+ async function askEc2Config(creds) {
107
+ console.log(chalk_1.default.yellow('Step 3: EC2 Configuration\n'));
108
+ const existing = await (0, aws_resources_1.listEc2Instances)(creds);
109
+ if (existing.length > 0) {
110
+ console.log(chalk_1.default.gray('Found existing EC2 instances:\n'));
111
+ existing.forEach((inst, i) => {
112
+ console.log(chalk_1.default.gray(` ${i + 1}. ${inst.name} (${inst.id}) - ${inst.type} - ${inst.state}`));
113
+ });
114
+ console.log('');
115
+ }
116
+ const { useExisting } = await inquirer_1.default.prompt([{
117
+ type: 'list',
118
+ name: 'useExisting',
119
+ message: 'How would you like to deploy?',
120
+ choices: [
121
+ { name: 'šŸ†• Create new EC2 instances (recommended for production)', value: false },
122
+ ...(existing.length > 0 ? [{ name: 'šŸ“¦ Use existing EC2 instance(s)', value: true }] : [])
123
+ ]
124
+ }]);
125
+ if (useExisting) {
126
+ const { selectedInstances } = await inquirer_1.default.prompt([{
127
+ type: 'checkbox',
128
+ name: 'selectedInstances',
129
+ message: 'Select instance(s) to deploy to:',
130
+ choices: existing.map(inst => ({
131
+ name: `${inst.name} (${inst.id}) - ${inst.type}`,
132
+ value: inst.id
133
+ })),
134
+ validate: (v) => v.length > 0 || 'Select at least one instance'
135
+ }]);
136
+ return { useExisting: true, existingInstanceIds: selectedInstances };
137
+ }
138
+ // New instances
139
+ console.log(chalk_1.default.gray('\nLet\'s configure your new instances:\n'));
140
+ const instanceTypes = Object.entries(types_1.PRICING.ec2).map(([type, price]) => ({
141
+ name: `${type} - $${(price * 730).toFixed(2)}/month (~$${price}/hr)`,
142
+ value: type
143
+ }));
144
+ const answers = await inquirer_1.default.prompt([
145
+ {
146
+ type: 'list',
147
+ name: 'instanceType',
148
+ message: 'Instance type:',
149
+ choices: instanceTypes,
150
+ default: 't3.small'
151
+ },
152
+ {
153
+ type: 'number',
154
+ name: 'minInstances',
155
+ message: 'Minimum instances (for auto-scaling):',
156
+ default: 1,
157
+ validate: (v) => v >= 1 || 'At least 1'
158
+ },
159
+ {
160
+ type: 'number',
161
+ name: 'maxInstances',
162
+ message: 'Maximum instances (for auto-scaling):',
163
+ default: 3,
164
+ validate: (v, answers) => v >= answers.minInstances || 'Must be >= minimum'
165
+ }
166
+ ]);
167
+ return { useExisting: false, ...answers };
168
+ }
169
+ async function askElasticIp(ec2) {
170
+ if (ec2.useExisting)
171
+ return false;
172
+ console.log(chalk_1.default.yellow('\nStep 4: Elastic IP\n'));
173
+ console.log(chalk_1.default.gray('An Elastic IP gives your instances a static public IP address.\n'));
174
+ console.log(chalk_1.default.cyan('Benefits:'));
175
+ console.log(chalk_1.default.gray(' • IP stays the same even if instance restarts'));
176
+ console.log(chalk_1.default.gray(' • Required if you want to point a domain directly to an instance'));
177
+ console.log(chalk_1.default.gray(' • Useful for whitelisting in firewalls\n'));
178
+ console.log(chalk_1.default.cyan('Cost:'));
179
+ console.log(chalk_1.default.gray(` • ${types_1.PRICING.elasticIp.note}`));
180
+ console.log(chalk_1.default.gray(' • With ALB (which we create), you typically don\'t need Elastic IPs\n'));
181
+ const { useElasticIp } = await inquirer_1.default.prompt([{
182
+ type: 'confirm',
183
+ name: 'useElasticIp',
184
+ message: 'Assign Elastic IP to each instance?',
185
+ default: false
186
+ }]);
187
+ return useElasticIp;
188
+ }
189
+ async function askDatabase(creds) {
190
+ console.log(chalk_1.default.yellow('\nStep 5: Database\n'));
191
+ const existing = await (0, aws_resources_1.listRdsInstances)(creds);
192
+ if (existing.length > 0) {
193
+ console.log(chalk_1.default.gray('Found existing RDS databases:\n'));
194
+ existing.forEach(db => {
195
+ console.log(chalk_1.default.gray(` • ${db.id} (${db.engine}) - ${db.instanceClass}`));
196
+ });
197
+ console.log('');
198
+ }
199
+ const { database } = await inquirer_1.default.prompt([{
200
+ type: 'list',
201
+ name: 'database',
202
+ message: 'Database:',
203
+ choices: [
204
+ { name: '🐘 PostgreSQL (recommended)', value: 'postgresql' },
205
+ { name: '🐬 MySQL', value: 'mysql' },
206
+ { name: 'āŒ No database', value: 'none' }
207
+ ]
208
+ }]);
209
+ if (database === 'none') {
210
+ return { database };
211
+ }
212
+ const dbTypes = Object.entries(types_1.PRICING.rds).map(([type, price]) => ({
213
+ name: `${type} - $${(price * 730).toFixed(2)}/month`,
214
+ value: type
215
+ }));
216
+ const { dbInstanceClass } = await inquirer_1.default.prompt([{
217
+ type: 'list',
218
+ name: 'dbInstanceClass',
219
+ message: 'Database instance size:',
220
+ choices: dbTypes,
221
+ default: 'db.t3.micro'
222
+ }]);
223
+ return { database, dbInstanceClass };
224
+ }
225
+ async function askDomain() {
226
+ console.log(chalk_1.default.yellow('\nStep 6: Domain & HTTPS\n'));
227
+ const { hasDomain } = await inquirer_1.default.prompt([{
228
+ type: 'confirm',
229
+ name: 'hasDomain',
230
+ message: 'Do you have a domain to use?',
231
+ default: false
232
+ }]);
233
+ if (!hasDomain) {
234
+ console.log(chalk_1.default.gray('\nNo problem! You\'ll get an ALB URL like: my-app-123456.us-east-1.elb.amazonaws.com\n'));
235
+ return { useHttps: false };
236
+ }
237
+ const { domain } = await inquirer_1.default.prompt([{
238
+ type: 'input',
239
+ name: 'domain',
240
+ message: 'Domain (e.g., api.myapp.com):',
241
+ validate: (v) => /^[a-z0-9.-]+\.[a-z]{2,}$/.test(v) || 'Enter a valid domain'
242
+ }]);
243
+ console.log(chalk_1.default.gray('\nHTTPS encrypts traffic between users and your app.'));
244
+ console.log(chalk_1.default.gray('We\'ll use AWS Certificate Manager (free) to provision an SSL certificate.\n'));
245
+ const { useHttps } = await inquirer_1.default.prompt([{
246
+ type: 'confirm',
247
+ name: 'useHttps',
248
+ message: 'Enable HTTPS?',
249
+ default: true
250
+ }]);
251
+ return { domain, useHttps };
252
+ }
253
+ async function showSummary(config) {
254
+ console.log(chalk_1.default.yellow('\nšŸ“‹ Deployment Summary\n'));
255
+ // Calculate costs
256
+ let monthlyCost = 0;
257
+ console.log(chalk_1.default.cyan('Infrastructure:'));
258
+ if (config.ec2.useExisting) {
259
+ console.log(chalk_1.default.gray(` • EC2: Using existing (${config.ec2.existingInstanceIds?.join(', ')})`));
260
+ }
261
+ else {
262
+ const ec2Cost = types_1.PRICING.ec2[config.ec2.instanceType] * 730 * config.ec2.minInstances;
263
+ monthlyCost += ec2Cost;
264
+ console.log(chalk_1.default.gray(` • EC2: ${config.ec2.minInstances}-${config.ec2.maxInstances} x ${config.ec2.instanceType} (~$${ec2Cost.toFixed(2)}/mo min)`));
265
+ }
266
+ if (config.useElasticIp) {
267
+ console.log(chalk_1.default.gray(` • Elastic IP: Yes (free when attached)`));
268
+ }
269
+ const albCost = types_1.PRICING.alb.perHour * 730;
270
+ monthlyCost += albCost;
271
+ console.log(chalk_1.default.gray(` • ALB: Yes (~$${albCost.toFixed(2)}/mo + LCU charges)`));
272
+ if (config.database !== 'none') {
273
+ const dbCost = types_1.PRICING.rds[config.dbInstanceClass] * 730;
274
+ monthlyCost += dbCost;
275
+ console.log(chalk_1.default.gray(` • RDS: ${config.database} ${config.dbInstanceClass} (~$${dbCost.toFixed(2)}/mo)`));
276
+ }
277
+ if (config.domain) {
278
+ console.log(chalk_1.default.gray(` • Domain: ${config.domain}`));
279
+ console.log(chalk_1.default.gray(` • HTTPS: ${config.useHttps ? 'Yes' : 'No'}`));
280
+ }
281
+ console.log(chalk_1.default.cyan(`\nEstimated minimum cost: ~$${monthlyCost.toFixed(2)}/month`));
282
+ console.log(chalk_1.default.gray('(Actual cost depends on usage, data transfer, etc.)\n'));
283
+ const { confirm } = await inquirer_1.default.prompt([{
284
+ type: 'confirm',
285
+ name: 'confirm',
286
+ message: 'Proceed with deployment?',
287
+ default: true
288
+ }]);
289
+ if (!confirm) {
290
+ console.log(chalk_1.default.yellow('Deployment cancelled.'));
291
+ process.exit(0);
292
+ }
293
+ }
@@ -0,0 +1,2 @@
1
+ import { ProjectInfo } from './types';
2
+ export declare function deploy(project: ProjectInfo): Promise<void>;
package/dist/deploy.js ADDED
@@ -0,0 +1,30 @@
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.deploy = deploy;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const conversation_1 = require("./conversation");
10
+ const infra_1 = require("./infra");
11
+ async function deploy(project) {
12
+ const config = await (0, conversation_1.runConversation)(project);
13
+ console.log(chalk_1.default.blue('\nšŸš€ Starting deployment...\n'));
14
+ const spinner = (0, ora_1.default)('Creating infrastructure...').start();
15
+ try {
16
+ const outputs = await (0, infra_1.deployInfra)(project, config);
17
+ spinner.succeed('Deployment complete!\n');
18
+ console.log(chalk_1.default.green('āœ“ Your app is live!\n'));
19
+ console.log(chalk_1.default.cyan('Endpoints:'));
20
+ console.log(chalk_1.default.gray(` • URL: ${outputs.url}`));
21
+ if (outputs.dbEndpoint) {
22
+ console.log(chalk_1.default.gray(` • Database: ${outputs.dbEndpoint}`));
23
+ }
24
+ console.log('');
25
+ }
26
+ catch (err) {
27
+ spinner.fail('Deployment failed');
28
+ throw err;
29
+ }
30
+ }
@@ -0,0 +1,3 @@
1
+ import { ProjectInfo } from './types';
2
+ export declare function detectNodeProject(dir: string): ProjectInfo;
3
+ export declare function detectSpringBootProject(dir: string): ProjectInfo;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.detectNodeProject = detectNodeProject;
37
+ exports.detectSpringBootProject = detectSpringBootProject;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ function detectNodeProject(dir) {
41
+ const pkgPath = path.join(dir, 'package.json');
42
+ if (!fs.existsSync(pkgPath)) {
43
+ throw new Error('No package.json found');
44
+ }
45
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
46
+ return {
47
+ type: 'nodejs',
48
+ name: pkg.name || path.basename(dir),
49
+ port: parseInt(process.env.PORT || '3000'),
50
+ buildCommand: pkg.scripts?.build ? 'npm run build' : '',
51
+ startCommand: pkg.scripts?.start || 'node index.js',
52
+ artifactPath: dir,
53
+ };
54
+ }
55
+ function detectSpringBootProject(dir) {
56
+ const pomPath = path.join(dir, 'pom.xml');
57
+ const gradlePath = path.join(dir, 'build.gradle');
58
+ const isGradle = fs.existsSync(gradlePath);
59
+ const isMaven = fs.existsSync(pomPath);
60
+ if (!isMaven && !isGradle) {
61
+ throw new Error('No pom.xml or build.gradle found');
62
+ }
63
+ const name = path.basename(dir);
64
+ return {
65
+ type: 'springboot',
66
+ name,
67
+ port: 8080,
68
+ buildCommand: isGradle ? './gradlew build' : 'mvn package',
69
+ startCommand: `java -jar target/${name}.jar`,
70
+ artifactPath: isGradle ? 'build/libs/*.jar' : 'target/*.jar',
71
+ };
72
+ }
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export { detectNodeProject, detectSpringBootProject } from './detector';
3
+ export { deploy } from './deploy';
4
+ export { runConversation } from './conversation';
5
+ export { validateCredentials, checkPermissions } from './aws-validator';
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.checkPermissions = exports.validateCredentials = exports.runConversation = exports.deploy = exports.detectSpringBootProject = exports.detectNodeProject = void 0;
18
+ __exportStar(require("./types"), exports);
19
+ var detector_1 = require("./detector");
20
+ Object.defineProperty(exports, "detectNodeProject", { enumerable: true, get: function () { return detector_1.detectNodeProject; } });
21
+ Object.defineProperty(exports, "detectSpringBootProject", { enumerable: true, get: function () { return detector_1.detectSpringBootProject; } });
22
+ var deploy_1 = require("./deploy");
23
+ Object.defineProperty(exports, "deploy", { enumerable: true, get: function () { return deploy_1.deploy; } });
24
+ var conversation_1 = require("./conversation");
25
+ Object.defineProperty(exports, "runConversation", { enumerable: true, get: function () { return conversation_1.runConversation; } });
26
+ var aws_validator_1 = require("./aws-validator");
27
+ Object.defineProperty(exports, "validateCredentials", { enumerable: true, get: function () { return aws_validator_1.validateCredentials; } });
28
+ Object.defineProperty(exports, "checkPermissions", { enumerable: true, get: function () { return aws_validator_1.checkPermissions; } });
@@ -0,0 +1,6 @@
1
+ import { ProjectInfo, DeployConfig } from './types';
2
+ export interface DeployOutputs {
3
+ url: string;
4
+ dbEndpoint?: string;
5
+ }
6
+ export declare function deployInfra(project: ProjectInfo, config: DeployConfig): Promise<DeployOutputs>;