@vibe-db/cli 1.0.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.
- package/BILLING_CLI.md +198 -0
- package/PUBLISHING.md +558 -0
- package/README.md +206 -0
- package/bin/vibedb.js +139 -0
- package/package.json +35 -0
- package/package.json.bak +35 -0
- package/src/api.js +196 -0
- package/src/commands/billing-cancel.js +89 -0
- package/src/commands/billing-info.js +101 -0
- package/src/commands/billing-invoices.js +103 -0
- package/src/commands/billing-subscribe.js +103 -0
- package/src/commands/init.js +62 -0
- package/src/commands/list.js +73 -0
- package/src/commands/login.js +53 -0
- package/src/commands/signup.js +73 -0
- package/src/config.js +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# VibeDB CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for VibeDB - instant database provisioning for AI-assisted development.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Via NPX (Recommended)
|
|
8
|
+
```bash
|
|
9
|
+
npx @vibedb/cli signup
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Global Installation
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @vibedb/cli
|
|
15
|
+
vibedb signup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Local Development
|
|
19
|
+
```bash
|
|
20
|
+
git clone <repo>
|
|
21
|
+
cd cli
|
|
22
|
+
npm install
|
|
23
|
+
node bin/vibedb.js --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Create an Account
|
|
29
|
+
```bash
|
|
30
|
+
npx @vibedb/cli signup
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
You'll be prompted for:
|
|
34
|
+
- Email address
|
|
35
|
+
- Password (minimum 8 characters)
|
|
36
|
+
- Password confirmation
|
|
37
|
+
|
|
38
|
+
Your API key will be saved to `~/.vibedb`
|
|
39
|
+
|
|
40
|
+
### 2. Or Login to Existing Account
|
|
41
|
+
```bash
|
|
42
|
+
npx @vibedb/cli login
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 3. Initialize Your Project
|
|
46
|
+
```bash
|
|
47
|
+
cd your-project
|
|
48
|
+
npx @vibedb/cli init
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This downloads `VIBEDB.md` to your current directory. This file tells your AI assistant how to provision databases.
|
|
52
|
+
|
|
53
|
+
### 4. Tell Your AI to Create a Database
|
|
54
|
+
Open your AI coding assistant (Claude, Cursor, etc.) and say:
|
|
55
|
+
|
|
56
|
+
> "I need a PostgreSQL database for my blog app"
|
|
57
|
+
|
|
58
|
+
The AI will read `VIBEDB.md`, use your API key from `~/.vibedb`, and provision a database automatically!
|
|
59
|
+
|
|
60
|
+
## Commands
|
|
61
|
+
|
|
62
|
+
### `vibedb signup`
|
|
63
|
+
Create a new VibeDB account.
|
|
64
|
+
|
|
65
|
+
**Interactive prompts:**
|
|
66
|
+
- Email
|
|
67
|
+
- Password
|
|
68
|
+
- Confirm password
|
|
69
|
+
|
|
70
|
+
**Output:**
|
|
71
|
+
- Account ID
|
|
72
|
+
- API key (saved to ~/.vibedb)
|
|
73
|
+
|
|
74
|
+
### `vibedb login`
|
|
75
|
+
Login to existing account.
|
|
76
|
+
|
|
77
|
+
**Interactive prompts:**
|
|
78
|
+
- Email
|
|
79
|
+
- Password
|
|
80
|
+
|
|
81
|
+
**Output:**
|
|
82
|
+
- API key (saved to ~/.vibedb)
|
|
83
|
+
|
|
84
|
+
### `vibedb init`
|
|
85
|
+
Download the VIBEDB.md prompt file to your project.
|
|
86
|
+
|
|
87
|
+
**Requirements:**
|
|
88
|
+
- Must be logged in (run `vibedb signup` or `vibedb login` first)
|
|
89
|
+
|
|
90
|
+
**Output:**
|
|
91
|
+
- Downloads `VIBEDB.md` to current directory
|
|
92
|
+
- Shows your configured API key
|
|
93
|
+
|
|
94
|
+
### `vibedb list` (alias: `ls`)
|
|
95
|
+
List all your databases.
|
|
96
|
+
|
|
97
|
+
**Requirements:**
|
|
98
|
+
- Must be logged in
|
|
99
|
+
|
|
100
|
+
**Output:**
|
|
101
|
+
- Table showing all databases with ID, Name, Type, and Status
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
The CLI stores your credentials in `~/.vibedb`:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"api_key": "vdb_xxx...",
|
|
110
|
+
"email": "you@example.com",
|
|
111
|
+
"api_url": "https://api.vibedb.dev"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Security Note:** Keep this file secure. Anyone with your API key can manage your databases.
|
|
116
|
+
|
|
117
|
+
## Examples
|
|
118
|
+
|
|
119
|
+
### Complete Workflow
|
|
120
|
+
```bash
|
|
121
|
+
# 1. Sign up
|
|
122
|
+
$ npx @vibedb/cli signup
|
|
123
|
+
? Email: john@example.com
|
|
124
|
+
? Password: ********
|
|
125
|
+
? Confirm password: ********
|
|
126
|
+
|
|
127
|
+
ā Account created successfully!
|
|
128
|
+
Email: john@example.com
|
|
129
|
+
API Key: vdb_abc123...
|
|
130
|
+
|
|
131
|
+
# 2. Initialize project
|
|
132
|
+
$ cd my-project
|
|
133
|
+
$ npx @vibedb/cli init
|
|
134
|
+
|
|
135
|
+
ā VIBEDB.md downloaded successfully!
|
|
136
|
+
Location: /path/to/my-project/VIBEDB.md
|
|
137
|
+
|
|
138
|
+
# 3. Tell your AI assistant
|
|
139
|
+
> "I need a Postgres database for user authentication"
|
|
140
|
+
|
|
141
|
+
# 4. Check your databases
|
|
142
|
+
$ npx @vibedb/cli list
|
|
143
|
+
|
|
144
|
+
āāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāā¬āāāāāāāāāāā¬āāāāāāāāā
|
|
145
|
+
ā ID ā Name ā Type ā Status ā
|
|
146
|
+
āāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāā¤
|
|
147
|
+
ā db_abc123 ā auth-db ā postgres ā ready ā
|
|
148
|
+
āāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāā“āāāāāāāāāāā“āāāāāāāāā
|
|
149
|
+
|
|
150
|
+
Total: 1 database
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Supported Databases
|
|
154
|
+
|
|
155
|
+
- **PostgreSQL** - General purpose relational database
|
|
156
|
+
- **MySQL** - Traditional relational database
|
|
157
|
+
- **Redis** - In-memory cache and session store
|
|
158
|
+
|
|
159
|
+
Coming soon:
|
|
160
|
+
- MongoDB
|
|
161
|
+
- ClickHouse
|
|
162
|
+
|
|
163
|
+
## Troubleshooting
|
|
164
|
+
|
|
165
|
+
### "Not logged in" Error
|
|
166
|
+
Run `vibedb login` or `vibedb signup` first.
|
|
167
|
+
|
|
168
|
+
### "Email already exists" During Signup
|
|
169
|
+
The email is already registered. Use `vibedb login` instead.
|
|
170
|
+
|
|
171
|
+
### "Invalid credentials" During Login
|
|
172
|
+
Check your email and password. Passwords are case-sensitive.
|
|
173
|
+
|
|
174
|
+
### API Connection Issues
|
|
175
|
+
- Check your internet connection
|
|
176
|
+
- Verify api.vibedb.dev is accessible
|
|
177
|
+
- Check firewall settings
|
|
178
|
+
|
|
179
|
+
### Config File Issues
|
|
180
|
+
Your config is at `~/.vibedb`. If corrupted:
|
|
181
|
+
```bash
|
|
182
|
+
rm ~/.vibedb
|
|
183
|
+
vibedb login
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## API Reference
|
|
187
|
+
|
|
188
|
+
The CLI interacts with these VibeDB API endpoints:
|
|
189
|
+
|
|
190
|
+
- `POST /v1/auth/signup` - Create account
|
|
191
|
+
- `POST /v1/auth/login` - Authenticate
|
|
192
|
+
- `GET /v1/databases` - List databases
|
|
193
|
+
- `GET /v1/prompt-file` - Download prompt file
|
|
194
|
+
- `GET /v1/account` - Get account info
|
|
195
|
+
|
|
196
|
+
Full API docs: https://api.vibedb.dev/docs
|
|
197
|
+
|
|
198
|
+
## Support
|
|
199
|
+
|
|
200
|
+
- Website: https://vibedb.dev
|
|
201
|
+
- Email: support@vibedb.dev
|
|
202
|
+
- Issues: https://github.com/vibedb/cli/issues
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT
|
package/bin/vibedb.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const signupCommand = require('../src/commands/signup');
|
|
6
|
+
const loginCommand = require('../src/commands/login');
|
|
7
|
+
const initCommand = require('../src/commands/init');
|
|
8
|
+
const listCommand = require('../src/commands/list');
|
|
9
|
+
const billingInfoCommand = require('../src/commands/billing-info');
|
|
10
|
+
const billingSubscribeCommand = require('../src/commands/billing-subscribe');
|
|
11
|
+
const billingCancelCommand = require('../src/commands/billing-cancel');
|
|
12
|
+
const billingInvoicesCommand = require('../src/commands/billing-invoices');
|
|
13
|
+
|
|
14
|
+
const program = new Command();
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.name('vibedb')
|
|
18
|
+
.description('VibeDB CLI - Instant database provisioning for AI-assisted development')
|
|
19
|
+
.version('1.0.0');
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command('signup')
|
|
23
|
+
.description('Create a new VibeDB account')
|
|
24
|
+
.action(async () => {
|
|
25
|
+
try {
|
|
26
|
+
await signupCommand();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command('login')
|
|
35
|
+
.description('Login to your VibeDB account')
|
|
36
|
+
.action(async () => {
|
|
37
|
+
try {
|
|
38
|
+
await loginCommand();
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.command('init')
|
|
47
|
+
.description('Download VIBEDB.md prompt file to your project')
|
|
48
|
+
.action(async () => {
|
|
49
|
+
try {
|
|
50
|
+
await initCommand();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
program
|
|
58
|
+
.command('list')
|
|
59
|
+
.alias('ls')
|
|
60
|
+
.description('List all your databases')
|
|
61
|
+
.action(async () => {
|
|
62
|
+
try {
|
|
63
|
+
await listCommand();
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Billing commands
|
|
71
|
+
const billing = program
|
|
72
|
+
.command('billing')
|
|
73
|
+
.description('Manage billing and subscriptions');
|
|
74
|
+
|
|
75
|
+
billing
|
|
76
|
+
.command('info')
|
|
77
|
+
.description('View billing information and subscription status')
|
|
78
|
+
.action(async () => {
|
|
79
|
+
try {
|
|
80
|
+
await billingInfoCommand();
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
billing
|
|
88
|
+
.command('subscribe')
|
|
89
|
+
.description('Subscribe to VibeDB')
|
|
90
|
+
.action(async () => {
|
|
91
|
+
try {
|
|
92
|
+
await billingSubscribeCommand();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
billing
|
|
100
|
+
.command('cancel')
|
|
101
|
+
.description('Cancel your subscription')
|
|
102
|
+
.action(async () => {
|
|
103
|
+
try {
|
|
104
|
+
await billingCancelCommand();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
billing
|
|
112
|
+
.command('invoices')
|
|
113
|
+
.description('View your invoices')
|
|
114
|
+
.action(async () => {
|
|
115
|
+
try {
|
|
116
|
+
await billingInvoicesCommand();
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error(chalk.red('Unexpected error:'), error.message);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Global error handler
|
|
124
|
+
process.on('unhandledRejection', (error) => {
|
|
125
|
+
console.error(chalk.red.bold('\nā Unhandled error:'), error.message);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
process.on('uncaughtException', (error) => {
|
|
130
|
+
console.error(chalk.red.bold('\nā Uncaught error:'), error.message);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
program.parse(process.argv);
|
|
135
|
+
|
|
136
|
+
// Show help if no command provided
|
|
137
|
+
if (!process.argv.slice(2).length) {
|
|
138
|
+
program.outputHelp();
|
|
139
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibe-db/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Command-line interface for VibeDB - instant database provisioning for AI-assisted development",
|
|
5
|
+
"main": "bin/vibedb.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"vibedb": "./bin/vibedb.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node bin/vibedb.js --help"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"database",
|
|
14
|
+
"postgres",
|
|
15
|
+
"mysql",
|
|
16
|
+
"redis",
|
|
17
|
+
"provisioning",
|
|
18
|
+
"cli",
|
|
19
|
+
"vibedb",
|
|
20
|
+
"ai",
|
|
21
|
+
"development"
|
|
22
|
+
],
|
|
23
|
+
"author": "VibeDB",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"axios": "^1.6.0",
|
|
27
|
+
"chalk": "^4.1.2",
|
|
28
|
+
"cli-table3": "^0.6.3",
|
|
29
|
+
"commander": "^11.0.0",
|
|
30
|
+
"inquirer": "^8.2.5"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/package.json.bak
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibedb/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Command-line interface for VibeDB - instant database provisioning for AI-assisted development",
|
|
5
|
+
"main": "bin/vibedb.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"vibedb": "./bin/vibedb.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node bin/vibedb.js --help"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"database",
|
|
14
|
+
"postgres",
|
|
15
|
+
"mysql",
|
|
16
|
+
"redis",
|
|
17
|
+
"provisioning",
|
|
18
|
+
"cli",
|
|
19
|
+
"vibedb",
|
|
20
|
+
"ai",
|
|
21
|
+
"development"
|
|
22
|
+
],
|
|
23
|
+
"author": "VibeDB",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"axios": "^1.6.0",
|
|
27
|
+
"chalk": "^4.1.2",
|
|
28
|
+
"cli-table3": "^0.6.3",
|
|
29
|
+
"commander": "^11.0.0",
|
|
30
|
+
"inquirer": "^8.2.5"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/api.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
const API_BASE_URL = 'https://api.vibedb.dev';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Signup a new user
|
|
7
|
+
*/
|
|
8
|
+
async function signup(email, password) {
|
|
9
|
+
try {
|
|
10
|
+
const response = await axios.post(`${API_BASE_URL}/v1/auth/signup`, {
|
|
11
|
+
email,
|
|
12
|
+
password,
|
|
13
|
+
});
|
|
14
|
+
return response.data;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error.response) {
|
|
17
|
+
const { error: errorCode, message } = error.response.data;
|
|
18
|
+
throw new Error(message || errorCode || 'Signup failed');
|
|
19
|
+
}
|
|
20
|
+
throw new Error(`Network error: ${error.message}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Login existing user
|
|
26
|
+
*/
|
|
27
|
+
async function login(email, password) {
|
|
28
|
+
try {
|
|
29
|
+
const response = await axios.post(`${API_BASE_URL}/v1/auth/login`, {
|
|
30
|
+
email,
|
|
31
|
+
password,
|
|
32
|
+
});
|
|
33
|
+
return response.data;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (error.response) {
|
|
36
|
+
const { error: errorCode, message } = error.response.data;
|
|
37
|
+
throw new Error(message || errorCode || 'Login failed');
|
|
38
|
+
}
|
|
39
|
+
throw new Error(`Network error: ${error.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* List all databases for authenticated user
|
|
45
|
+
*/
|
|
46
|
+
async function listDatabases(apiKey) {
|
|
47
|
+
try {
|
|
48
|
+
const response = await axios.get(`${API_BASE_URL}/v1/databases`, {
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Bearer ${apiKey}`,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
return response.data.databases || [];
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error.response) {
|
|
56
|
+
const { error: errorCode, message } = error.response.data;
|
|
57
|
+
throw new Error(message || errorCode || 'Failed to list databases');
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Network error: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get prompt file content
|
|
65
|
+
*/
|
|
66
|
+
async function getPromptFile() {
|
|
67
|
+
try {
|
|
68
|
+
const response = await axios.get(`${API_BASE_URL}/v1/prompt-file`);
|
|
69
|
+
return response.data;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error.response) {
|
|
72
|
+
throw new Error('Failed to download prompt file');
|
|
73
|
+
}
|
|
74
|
+
throw new Error(`Network error: ${error.message}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get account information
|
|
80
|
+
*/
|
|
81
|
+
async function getAccount(apiKey) {
|
|
82
|
+
try {
|
|
83
|
+
const response = await axios.get(`${API_BASE_URL}/v1/account`, {
|
|
84
|
+
headers: {
|
|
85
|
+
Authorization: `Bearer ${apiKey}`,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
return response.data;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error.response) {
|
|
91
|
+
const { error: errorCode, message } = error.response.data;
|
|
92
|
+
throw new Error(message || errorCode || 'Failed to get account info');
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`Network error: ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get billing information
|
|
100
|
+
*/
|
|
101
|
+
async function getBillingInfo(apiKey) {
|
|
102
|
+
try {
|
|
103
|
+
const response = await axios.get(`${API_BASE_URL}/v1/billing/info`, {
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: `Bearer ${apiKey}`,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
return response.data;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
if (error.response) {
|
|
111
|
+
const { error: errorCode, message } = error.response.data;
|
|
112
|
+
throw new Error(message || errorCode || 'Failed to get billing info');
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Network error: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Create subscription
|
|
120
|
+
*/
|
|
121
|
+
async function createSubscription(apiKey, priceId = null) {
|
|
122
|
+
try {
|
|
123
|
+
const response = await axios.post(
|
|
124
|
+
`${API_BASE_URL}/v1/billing/subscribe`,
|
|
125
|
+
priceId ? { price_id: priceId } : {},
|
|
126
|
+
{
|
|
127
|
+
headers: {
|
|
128
|
+
Authorization: `Bearer ${apiKey}`,
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
return response.data;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error.response) {
|
|
135
|
+
const { error: errorCode, message } = error.response.data;
|
|
136
|
+
throw new Error(message || errorCode || 'Failed to create subscription');
|
|
137
|
+
}
|
|
138
|
+
throw new Error(`Network error: ${error.message}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Cancel subscription
|
|
144
|
+
*/
|
|
145
|
+
async function cancelSubscription(apiKey) {
|
|
146
|
+
try {
|
|
147
|
+
const response = await axios.post(
|
|
148
|
+
`${API_BASE_URL}/v1/billing/cancel`,
|
|
149
|
+
{},
|
|
150
|
+
{
|
|
151
|
+
headers: {
|
|
152
|
+
Authorization: `Bearer ${apiKey}`,
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
return response.data;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (error.response) {
|
|
159
|
+
const { error: errorCode, message } = error.response.data;
|
|
160
|
+
throw new Error(message || errorCode || 'Failed to cancel subscription');
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`Network error: ${error.message}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get invoices
|
|
168
|
+
*/
|
|
169
|
+
async function getInvoices(apiKey) {
|
|
170
|
+
try {
|
|
171
|
+
const response = await axios.get(`${API_BASE_URL}/v1/billing/invoices`, {
|
|
172
|
+
headers: {
|
|
173
|
+
Authorization: `Bearer ${apiKey}`,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
return response.data;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (error.response) {
|
|
179
|
+
const { error: errorCode, message } = error.response.data;
|
|
180
|
+
throw new Error(message || errorCode || 'Failed to get invoices');
|
|
181
|
+
}
|
|
182
|
+
throw new Error(`Network error: ${error.message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = {
|
|
187
|
+
signup,
|
|
188
|
+
login,
|
|
189
|
+
listDatabases,
|
|
190
|
+
getPromptFile,
|
|
191
|
+
getAccount,
|
|
192
|
+
getBillingInfo,
|
|
193
|
+
createSubscription,
|
|
194
|
+
cancelSubscription,
|
|
195
|
+
getInvoices,
|
|
196
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const api = require('../api');
|
|
4
|
+
const config = require('../config');
|
|
5
|
+
|
|
6
|
+
async function billingCancelCommand() {
|
|
7
|
+
console.log(chalk.blue.bold('\nš³ Cancel Subscription\n'));
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
// Check if logged in
|
|
11
|
+
if (!config.isLoggedIn()) {
|
|
12
|
+
console.error(chalk.red.bold('ā Not logged in'));
|
|
13
|
+
console.log(chalk.gray('\nPlease run'), chalk.cyan('vibedb login'), chalk.gray('or'), chalk.cyan('vibedb signup'), chalk.gray('first.'));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const apiKey = config.getAPIKey();
|
|
18
|
+
|
|
19
|
+
// Check current billing info
|
|
20
|
+
console.log(chalk.gray('Checking current subscription...\n'));
|
|
21
|
+
|
|
22
|
+
let billingInfo;
|
|
23
|
+
try {
|
|
24
|
+
billingInfo = await api.getBillingInfo(apiKey);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error.message.includes('503') || error.message.includes('billing_unavailable')) {
|
|
27
|
+
console.error(chalk.red.bold('ā Billing not available'));
|
|
28
|
+
console.log(chalk.gray('Stripe billing is not configured on the server.'));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if has active subscription
|
|
35
|
+
if (!billingInfo.subscription || billingInfo.subscription.status !== 'active') {
|
|
36
|
+
console.log(chalk.yellow('ā No active subscription found'));
|
|
37
|
+
console.log(chalk.gray('Nothing to cancel.'));
|
|
38
|
+
console.log();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const sub = billingInfo.subscription;
|
|
43
|
+
|
|
44
|
+
// Show current subscription
|
|
45
|
+
console.log(chalk.white.bold('Current Subscription:'));
|
|
46
|
+
console.log(chalk.gray('Status:'), chalk.green('Active'));
|
|
47
|
+
console.log(chalk.gray('Period ends:'), chalk.white(new Date(sub.current_period_end).toLocaleDateString()));
|
|
48
|
+
console.log();
|
|
49
|
+
|
|
50
|
+
// Confirm cancellation
|
|
51
|
+
console.log(chalk.yellow.bold('ā Warning:'));
|
|
52
|
+
console.log(chalk.gray('Your subscription will remain active until'), chalk.white(new Date(sub.current_period_end).toLocaleDateString()));
|
|
53
|
+
console.log(chalk.gray('After that, your databases may be paused or limited.'));
|
|
54
|
+
console.log();
|
|
55
|
+
|
|
56
|
+
const { confirm } = await inquirer.prompt([
|
|
57
|
+
{
|
|
58
|
+
type: 'confirm',
|
|
59
|
+
name: 'confirm',
|
|
60
|
+
message: 'Are you sure you want to cancel?',
|
|
61
|
+
default: false,
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
if (!confirm) {
|
|
66
|
+
console.log(chalk.gray('\nCancellation aborted.'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(chalk.gray('\nCancelling subscription...'));
|
|
71
|
+
|
|
72
|
+
const result = await api.cancelSubscription(apiKey);
|
|
73
|
+
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(chalk.green.bold('ā Subscription cancelled'));
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.gray('Status:'), chalk.yellow(result.status));
|
|
78
|
+
console.log(chalk.gray('Access until:'), chalk.white(new Date(result.current_period_end).toLocaleDateString()));
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.gray('You can resubscribe anytime with:'), chalk.cyan('vibedb billing subscribe'));
|
|
81
|
+
console.log();
|
|
82
|
+
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(chalk.red.bold('\nā Failed to cancel subscription:'), chalk.red(error.message));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = billingCancelCommand;
|