@stephendolan/chartmogul-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/LICENSE +21 -0
- package/README.md +238 -0
- package/dist/cli.js +615 -0
- package/dist/cli.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Stephen Dolan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# ChartMogul CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@stephendolan/chartmogul-cli)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A command-line interface for ChartMogul analytics, designed for developers and LLMs.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **LLM-first design** - JSON output for easy parsing and automation
|
|
11
|
+
- **Analytics focused** - MRR, ARR, churn rates, LTV, customer counts
|
|
12
|
+
- **Secure auth** - Credentials stored in OS keychain
|
|
13
|
+
- **Read-only** - Query your data safely without risk of modification
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### From npm (recommended)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @stephendolan/chartmogul-cli
|
|
21
|
+
# or
|
|
22
|
+
bun install -g @stephendolan/chartmogul-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### From source
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/stephendolan/chartmogul-cli.git
|
|
29
|
+
cd chartmogul-cli
|
|
30
|
+
bun install
|
|
31
|
+
bun run link
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Linux prerequisites
|
|
35
|
+
|
|
36
|
+
On Linux, install libsecret for keychain support:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
sudo apt-get install libsecret-1-dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Authentication
|
|
43
|
+
|
|
44
|
+
### Using API Key (recommended)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Store API key in OS keychain
|
|
48
|
+
chartmogul auth login --api-key YOUR_API_KEY
|
|
49
|
+
|
|
50
|
+
# Check authentication status
|
|
51
|
+
chartmogul auth status
|
|
52
|
+
|
|
53
|
+
# Remove stored credentials
|
|
54
|
+
chartmogul auth logout
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Using environment variable
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export CHARTMOGUL_API_KEY=your_api_key
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Get your API key from ChartMogul: Profile → API Keys
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Account
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# View account details
|
|
71
|
+
chartmogul account view
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Metrics
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Get all metrics (last 30 days by default)
|
|
78
|
+
chartmogul metrics all
|
|
79
|
+
|
|
80
|
+
# MRR (Monthly Recurring Revenue)
|
|
81
|
+
chartmogul metrics mrr
|
|
82
|
+
chartmogul metrics mrr --start-date 2024-01-01 --end-date 2024-12-31
|
|
83
|
+
|
|
84
|
+
# ARR (Annual Recurring Revenue)
|
|
85
|
+
chartmogul metrics arr --interval month
|
|
86
|
+
|
|
87
|
+
# ARPA (Average Revenue Per Account)
|
|
88
|
+
chartmogul metrics arpa
|
|
89
|
+
|
|
90
|
+
# ASP (Average Sale Price)
|
|
91
|
+
chartmogul metrics asp
|
|
92
|
+
|
|
93
|
+
# Customer count
|
|
94
|
+
chartmogul metrics customer-count
|
|
95
|
+
|
|
96
|
+
# Customer churn rate
|
|
97
|
+
chartmogul metrics customer-churn
|
|
98
|
+
|
|
99
|
+
# MRR churn rate
|
|
100
|
+
chartmogul metrics mrr-churn
|
|
101
|
+
|
|
102
|
+
# LTV (Customer Lifetime Value)
|
|
103
|
+
chartmogul metrics ltv
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Customers
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# List customers
|
|
110
|
+
chartmogul customers list
|
|
111
|
+
chartmogul customers list --status Active
|
|
112
|
+
chartmogul customers list --data-source <uuid>
|
|
113
|
+
|
|
114
|
+
# View a customer
|
|
115
|
+
chartmogul customers view <uuid>
|
|
116
|
+
|
|
117
|
+
# Search by email
|
|
118
|
+
chartmogul customers search --email user@example.com
|
|
119
|
+
|
|
120
|
+
# View customer activities
|
|
121
|
+
chartmogul customers activities <uuid>
|
|
122
|
+
|
|
123
|
+
# View customer subscriptions
|
|
124
|
+
chartmogul customers subscriptions <uuid>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Plans
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# List plans
|
|
131
|
+
chartmogul plans list
|
|
132
|
+
|
|
133
|
+
# View a plan
|
|
134
|
+
chartmogul plans view <uuid>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Invoices
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# List invoices
|
|
141
|
+
chartmogul invoices list
|
|
142
|
+
chartmogul invoices list --customer <uuid>
|
|
143
|
+
|
|
144
|
+
# View an invoice
|
|
145
|
+
chartmogul invoices view <uuid>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Data Sources
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# List data sources
|
|
152
|
+
chartmogul data-sources list
|
|
153
|
+
|
|
154
|
+
# View a data source
|
|
155
|
+
chartmogul data-sources view <uuid>
|
|
156
|
+
|
|
157
|
+
# Set default data source for filtering
|
|
158
|
+
chartmogul data-sources set-default <uuid>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Activities
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# List activities
|
|
165
|
+
chartmogul activities list
|
|
166
|
+
chartmogul activities list --type new_biz
|
|
167
|
+
chartmogul activities list --start-date 2024-01-01 --end-date 2024-12-31
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Output Formatting
|
|
171
|
+
|
|
172
|
+
All commands output JSON by default:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Pretty-printed JSON (default)
|
|
176
|
+
chartmogul metrics mrr
|
|
177
|
+
|
|
178
|
+
# Compact JSON (single line)
|
|
179
|
+
chartmogul -c metrics mrr
|
|
180
|
+
chartmogul --compact customers list
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Environment Variables
|
|
184
|
+
|
|
185
|
+
| Variable | Description |
|
|
186
|
+
|----------|-------------|
|
|
187
|
+
| `CHARTMOGUL_API_KEY` | API key (alternative to keychain) |
|
|
188
|
+
| `CHARTMOGUL_DATA_SOURCE` | Default data source UUID |
|
|
189
|
+
|
|
190
|
+
## Common Patterns
|
|
191
|
+
|
|
192
|
+
### Get current MRR
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
chartmogul metrics mrr --start-date $(date +%Y-%m-%d) --end-date $(date +%Y-%m-%d)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Get monthly MRR trend
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
chartmogul metrics mrr --start-date 2024-01-01 --end-date 2024-12-31 --interval month
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Find high-value customers
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
chartmogul customers list | jq '.entries | sort_by(.mrr) | reverse | .[0:10]'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Get churn analysis
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
chartmogul metrics customer-churn --start-date 2024-01-01 --end-date 2024-12-31 --interval month
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### View recent activities
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
chartmogul activities list --type churn --start-date 2024-12-01
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Error Handling
|
|
223
|
+
|
|
224
|
+
Errors are returned as JSON:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"error": {
|
|
229
|
+
"name": "unauthorized",
|
|
230
|
+
"detail": "Invalid API key",
|
|
231
|
+
"statusCode": 401
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
MIT
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/lib/output.ts
|
|
7
|
+
var globalOutputOptions = {};
|
|
8
|
+
function setOutputOptions(options) {
|
|
9
|
+
globalOutputOptions = options;
|
|
10
|
+
}
|
|
11
|
+
function outputJson(data, options = {}) {
|
|
12
|
+
const mergedOptions = { ...globalOutputOptions, ...options };
|
|
13
|
+
const jsonString = mergedOptions.compact ? JSON.stringify(data) : JSON.stringify(data, null, 2);
|
|
14
|
+
console.log(jsonString);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/commands/auth.ts
|
|
18
|
+
import { Command } from "commander";
|
|
19
|
+
|
|
20
|
+
// src/lib/auth.ts
|
|
21
|
+
import { Entry } from "@napi-rs/keyring";
|
|
22
|
+
|
|
23
|
+
// src/lib/config.ts
|
|
24
|
+
import Conf from "conf";
|
|
25
|
+
var store = new Conf({
|
|
26
|
+
projectName: "chartmogul-cli"
|
|
27
|
+
});
|
|
28
|
+
var config = {
|
|
29
|
+
getDefaultDataSource() {
|
|
30
|
+
return store.get("defaultDataSource") || process.env.CHARTMOGUL_DATA_SOURCE;
|
|
31
|
+
},
|
|
32
|
+
setDefaultDataSource(dataSourceUuid) {
|
|
33
|
+
store.set("defaultDataSource", dataSourceUuid);
|
|
34
|
+
},
|
|
35
|
+
clearDefaultDataSource() {
|
|
36
|
+
store.delete("defaultDataSource");
|
|
37
|
+
},
|
|
38
|
+
clear() {
|
|
39
|
+
store.clear();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/lib/auth.ts
|
|
44
|
+
var SERVICE_NAME = "chartmogul-cli";
|
|
45
|
+
var API_KEY_ACCOUNT = "api-key";
|
|
46
|
+
var KEYRING_UNAVAILABLE_ERROR = "Keychain storage unavailable. Cannot store credentials securely.\nOn Linux, install libsecret: sudo apt-get install libsecret-1-dev\nThen reinstall: bun install -g @stephendolan/chartmogul-cli\nAlternatively, use CHARTMOGUL_API_KEY environment variable.";
|
|
47
|
+
function getKeyring(account) {
|
|
48
|
+
try {
|
|
49
|
+
return new Entry(SERVICE_NAME, account);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function getPassword(account) {
|
|
55
|
+
const entry = getKeyring(account);
|
|
56
|
+
if (entry) {
|
|
57
|
+
try {
|
|
58
|
+
return entry.getPassword();
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function setPassword(account, value) {
|
|
66
|
+
const entry = getKeyring(account);
|
|
67
|
+
if (!entry) {
|
|
68
|
+
throw new Error(KEYRING_UNAVAILABLE_ERROR);
|
|
69
|
+
}
|
|
70
|
+
entry.setPassword(value);
|
|
71
|
+
}
|
|
72
|
+
function deletePassword(account) {
|
|
73
|
+
const entry = getKeyring(account);
|
|
74
|
+
if (entry) {
|
|
75
|
+
return entry.deletePassword();
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
var AuthManager = class {
|
|
80
|
+
getApiKey() {
|
|
81
|
+
return getPassword(API_KEY_ACCOUNT) || process.env.CHARTMOGUL_API_KEY || null;
|
|
82
|
+
}
|
|
83
|
+
setApiKey(apiKey) {
|
|
84
|
+
setPassword(API_KEY_ACCOUNT, apiKey);
|
|
85
|
+
}
|
|
86
|
+
isAuthenticated() {
|
|
87
|
+
return this.getApiKey() !== null;
|
|
88
|
+
}
|
|
89
|
+
logout() {
|
|
90
|
+
deletePassword(API_KEY_ACCOUNT);
|
|
91
|
+
config.clearDefaultDataSource();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var auth = new AuthManager();
|
|
95
|
+
|
|
96
|
+
// src/lib/errors.ts
|
|
97
|
+
var ChartMogulCliError = class extends Error {
|
|
98
|
+
constructor(message, statusCode) {
|
|
99
|
+
super(message);
|
|
100
|
+
this.statusCode = statusCode;
|
|
101
|
+
this.name = "ChartMogulCliError";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var ChartMogulApiError = class extends Error {
|
|
105
|
+
constructor(message, apiError, statusCode) {
|
|
106
|
+
super(message);
|
|
107
|
+
this.apiError = apiError;
|
|
108
|
+
this.statusCode = statusCode;
|
|
109
|
+
this.name = "ChartMogulApiError";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
function sanitizeErrorMessage(message) {
|
|
113
|
+
const sensitivePatterns = [
|
|
114
|
+
/Bearer\s+[\w\-._~+/]+=*/gi,
|
|
115
|
+
/token[=:]\s*[\w\-._~+/]+=*/gi,
|
|
116
|
+
/api[_-]?key[=:]\s*[\w\-._~+/]+=*/gi,
|
|
117
|
+
/authorization:\s*basic\s+[\w\-._~+/]+=*/gi
|
|
118
|
+
];
|
|
119
|
+
let sanitized = message;
|
|
120
|
+
for (const pattern of sensitivePatterns) {
|
|
121
|
+
sanitized = sanitized.replace(pattern, "[REDACTED]");
|
|
122
|
+
}
|
|
123
|
+
return sanitized.length > 500 ? sanitized.substring(0, 500) + "..." : sanitized;
|
|
124
|
+
}
|
|
125
|
+
function isErrorObject(value) {
|
|
126
|
+
return typeof value === "object" && value !== null;
|
|
127
|
+
}
|
|
128
|
+
function sanitizeApiError(error) {
|
|
129
|
+
if (!isErrorObject(error)) {
|
|
130
|
+
return {
|
|
131
|
+
name: "api_error",
|
|
132
|
+
detail: "An error occurred"
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const apiError = error;
|
|
136
|
+
let detail = "An error occurred";
|
|
137
|
+
if (apiError.message) {
|
|
138
|
+
detail = apiError.message;
|
|
139
|
+
} else if (apiError.errors?.length) {
|
|
140
|
+
detail = apiError.errors.map((e) => e.message || e.key).filter(Boolean).join("; ");
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
name: apiError.error || "api_error",
|
|
144
|
+
detail: sanitizeErrorMessage(detail)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function formatErrorResponse(name, detail, statusCode) {
|
|
148
|
+
const hint = name === "too_many_requests" ? "ChartMogul API rate limit exceeded. Wait a moment and retry." : void 0;
|
|
149
|
+
const response = {
|
|
150
|
+
error: { name, detail, statusCode }
|
|
151
|
+
};
|
|
152
|
+
if (hint) {
|
|
153
|
+
response.hint = hint;
|
|
154
|
+
}
|
|
155
|
+
outputJson(response);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
function handleChartMogulError(error) {
|
|
159
|
+
if (error instanceof ChartMogulCliError) {
|
|
160
|
+
const sanitized = sanitizeErrorMessage(error.message);
|
|
161
|
+
formatErrorResponse("cli_error", sanitized, error.statusCode || 1);
|
|
162
|
+
}
|
|
163
|
+
if (error instanceof ChartMogulApiError) {
|
|
164
|
+
const cmError = sanitizeApiError(error.apiError);
|
|
165
|
+
formatErrorResponse(cmError.name, cmError.detail, error.statusCode);
|
|
166
|
+
}
|
|
167
|
+
if (error instanceof Error) {
|
|
168
|
+
const sanitized = sanitizeErrorMessage(error.message);
|
|
169
|
+
formatErrorResponse("unknown_error", sanitized, 1);
|
|
170
|
+
}
|
|
171
|
+
formatErrorResponse("unknown_error", "An unexpected error occurred", 1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/lib/api-client.ts
|
|
175
|
+
var API_BASE = "https://api.chartmogul.com/v1";
|
|
176
|
+
var ChartMogulClient = class {
|
|
177
|
+
getAuthHeader() {
|
|
178
|
+
const apiKey = auth.getApiKey();
|
|
179
|
+
if (!apiKey) {
|
|
180
|
+
throw new ChartMogulCliError("Not authenticated. Please run: chartmogul auth login", 401);
|
|
181
|
+
}
|
|
182
|
+
return `Basic ${Buffer.from(`${apiKey}:`).toString("base64")}`;
|
|
183
|
+
}
|
|
184
|
+
async request(method, path, options = {}) {
|
|
185
|
+
const { params, body } = options;
|
|
186
|
+
const url = new URL(`${API_BASE}${path}`);
|
|
187
|
+
if (params) {
|
|
188
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
189
|
+
if (value !== void 0) {
|
|
190
|
+
url.searchParams.set(key, String(value));
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const authHeader = this.getAuthHeader();
|
|
195
|
+
const fetchOptions = {
|
|
196
|
+
method,
|
|
197
|
+
headers: {
|
|
198
|
+
Authorization: authHeader,
|
|
199
|
+
"Content-Type": "application/json"
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
if (body) {
|
|
203
|
+
fetchOptions.body = JSON.stringify(body);
|
|
204
|
+
}
|
|
205
|
+
let response;
|
|
206
|
+
try {
|
|
207
|
+
response = await fetch(url.toString(), fetchOptions);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
const message = error instanceof Error ? error.message : "Unknown network error";
|
|
210
|
+
throw new ChartMogulCliError(`Network request failed: ${message}`, 0);
|
|
211
|
+
}
|
|
212
|
+
if (response.status === 429) {
|
|
213
|
+
const retryAfter = response.headers.get("Retry-After") || "60";
|
|
214
|
+
throw new ChartMogulCliError(
|
|
215
|
+
`Rate limited by ChartMogul API. Retry after ${retryAfter} seconds.`,
|
|
216
|
+
429
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
if (response.status === 204) {
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
const error = await response.json().catch(() => ({}));
|
|
224
|
+
throw new ChartMogulApiError("API request failed", error, response.status);
|
|
225
|
+
}
|
|
226
|
+
return response.json();
|
|
227
|
+
}
|
|
228
|
+
async getAccount() {
|
|
229
|
+
return this.request("GET", "/account");
|
|
230
|
+
}
|
|
231
|
+
async ping() {
|
|
232
|
+
return this.request("GET", "/ping");
|
|
233
|
+
}
|
|
234
|
+
async listDataSources() {
|
|
235
|
+
return this.request("GET", "/data_sources");
|
|
236
|
+
}
|
|
237
|
+
async getDataSource(uuid) {
|
|
238
|
+
return this.request("GET", `/data_sources/${uuid}`);
|
|
239
|
+
}
|
|
240
|
+
async listCustomers(params = {}) {
|
|
241
|
+
return this.request("GET", "/customers", { params });
|
|
242
|
+
}
|
|
243
|
+
async getCustomer(uuid) {
|
|
244
|
+
return this.request("GET", `/customers/${uuid}`);
|
|
245
|
+
}
|
|
246
|
+
async searchCustomers(email) {
|
|
247
|
+
return this.request("GET", "/customers/search", {
|
|
248
|
+
params: { email }
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async getCustomerActivities(uuid, params = {}) {
|
|
252
|
+
return this.request("GET", `/customers/${uuid}/activities`, {
|
|
253
|
+
params
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
async getCustomerSubscriptions(uuid) {
|
|
257
|
+
return this.request("GET", `/customers/${uuid}/subscriptions`);
|
|
258
|
+
}
|
|
259
|
+
async listPlans(params = {}) {
|
|
260
|
+
return this.request(
|
|
261
|
+
"GET",
|
|
262
|
+
"/plans",
|
|
263
|
+
{ params }
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
async getPlan(uuid) {
|
|
267
|
+
return this.request("GET", `/plans/${uuid}`);
|
|
268
|
+
}
|
|
269
|
+
async listInvoices(params = {}) {
|
|
270
|
+
return this.request("GET", "/invoices", { params });
|
|
271
|
+
}
|
|
272
|
+
async getInvoice(uuid) {
|
|
273
|
+
return this.request("GET", `/invoices/${uuid}`);
|
|
274
|
+
}
|
|
275
|
+
async getMrr(params) {
|
|
276
|
+
return this.request("GET", "/metrics/mrr", { params });
|
|
277
|
+
}
|
|
278
|
+
async getArr(params) {
|
|
279
|
+
return this.request("GET", "/metrics/arr", { params });
|
|
280
|
+
}
|
|
281
|
+
async getArpa(params) {
|
|
282
|
+
return this.request("GET", "/metrics/arpa", { params });
|
|
283
|
+
}
|
|
284
|
+
async getAsp(params) {
|
|
285
|
+
return this.request("GET", "/metrics/asp", { params });
|
|
286
|
+
}
|
|
287
|
+
async getCustomerCount(params) {
|
|
288
|
+
return this.request("GET", "/metrics/customer-count", { params });
|
|
289
|
+
}
|
|
290
|
+
async getCustomerChurnRate(params) {
|
|
291
|
+
return this.request("GET", "/metrics/customer-churn-rate", { params });
|
|
292
|
+
}
|
|
293
|
+
async getMrrChurnRate(params) {
|
|
294
|
+
return this.request("GET", "/metrics/mrr-churn-rate", { params });
|
|
295
|
+
}
|
|
296
|
+
async getLtv(params) {
|
|
297
|
+
return this.request("GET", "/metrics/ltv", { params });
|
|
298
|
+
}
|
|
299
|
+
async getAllMetrics(params) {
|
|
300
|
+
return this.request("GET", "/metrics/all", { params });
|
|
301
|
+
}
|
|
302
|
+
async listActivities(params = {}) {
|
|
303
|
+
return this.request("GET", "/activities", { params });
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
var client = new ChartMogulClient();
|
|
307
|
+
|
|
308
|
+
// src/lib/command-utils.ts
|
|
309
|
+
function withErrorHandling(fn) {
|
|
310
|
+
return async (...args) => {
|
|
311
|
+
try {
|
|
312
|
+
await fn(...args);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
handleChartMogulError(error);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/commands/auth.ts
|
|
320
|
+
function createAuthCommand() {
|
|
321
|
+
const cmd = new Command("auth").description("Authentication operations");
|
|
322
|
+
cmd.command("login").description("Configure ChartMogul API credentials").requiredOption("--api-key <key>", "ChartMogul API Key").action(
|
|
323
|
+
withErrorHandling(async (options) => {
|
|
324
|
+
auth.setApiKey(options.apiKey);
|
|
325
|
+
await client.ping();
|
|
326
|
+
outputJson({ message: "Successfully authenticated with ChartMogul" });
|
|
327
|
+
})
|
|
328
|
+
);
|
|
329
|
+
cmd.command("logout").description("Remove stored credentials").action(
|
|
330
|
+
withErrorHandling(async () => {
|
|
331
|
+
auth.logout();
|
|
332
|
+
outputJson({ message: "Logged out successfully" });
|
|
333
|
+
})
|
|
334
|
+
);
|
|
335
|
+
cmd.command("status").description("Check authentication status").action(
|
|
336
|
+
withErrorHandling(async () => {
|
|
337
|
+
outputJson({ authenticated: auth.isAuthenticated() });
|
|
338
|
+
})
|
|
339
|
+
);
|
|
340
|
+
return cmd;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/commands/account.ts
|
|
344
|
+
import { Command as Command2 } from "commander";
|
|
345
|
+
function createAccountCommand() {
|
|
346
|
+
const cmd = new Command2("account").description("Account operations");
|
|
347
|
+
cmd.command("view").description("View account details").action(
|
|
348
|
+
withErrorHandling(async () => {
|
|
349
|
+
const account = await client.getAccount();
|
|
350
|
+
outputJson(account);
|
|
351
|
+
})
|
|
352
|
+
);
|
|
353
|
+
return cmd;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/commands/data-sources.ts
|
|
357
|
+
import { Command as Command3 } from "commander";
|
|
358
|
+
function createDataSourcesCommand() {
|
|
359
|
+
const cmd = new Command3("data-sources").description("Data source operations");
|
|
360
|
+
cmd.command("list").description("List all data sources").action(
|
|
361
|
+
withErrorHandling(async () => {
|
|
362
|
+
const result = await client.listDataSources();
|
|
363
|
+
outputJson(result.data_sources);
|
|
364
|
+
})
|
|
365
|
+
);
|
|
366
|
+
cmd.command("view").description("View a data source").argument("<uuid>", "Data source UUID").action(
|
|
367
|
+
withErrorHandling(async (uuid) => {
|
|
368
|
+
const dataSource = await client.getDataSource(uuid);
|
|
369
|
+
outputJson(dataSource);
|
|
370
|
+
})
|
|
371
|
+
);
|
|
372
|
+
cmd.command("set-default").description("Set default data source for filtering").argument("<uuid>", "Data source UUID").action(
|
|
373
|
+
withErrorHandling(async (uuid) => {
|
|
374
|
+
config.setDefaultDataSource(uuid);
|
|
375
|
+
outputJson({ message: `Default data source set to ${uuid}` });
|
|
376
|
+
})
|
|
377
|
+
);
|
|
378
|
+
cmd.command("get-default").description("Get default data source").action(
|
|
379
|
+
withErrorHandling(async () => {
|
|
380
|
+
const defaultDs = config.getDefaultDataSource();
|
|
381
|
+
outputJson({ default_data_source: defaultDs || null });
|
|
382
|
+
})
|
|
383
|
+
);
|
|
384
|
+
return cmd;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/commands/customers.ts
|
|
388
|
+
import { Command as Command4 } from "commander";
|
|
389
|
+
function createCustomersCommand() {
|
|
390
|
+
const cmd = new Command4("customers").description("Customer queries");
|
|
391
|
+
cmd.command("list").description("List customers").option("--data-source <uuid>", "Filter by data source UUID").option("--status <status>", "Filter by status (Lead, Active, Cancelled)").option("--external-id <id>", "Filter by external ID").option("--page <number>", "Page number").option("--per-page <number>", "Results per page (max 200)").action(
|
|
392
|
+
withErrorHandling(
|
|
393
|
+
async (options) => {
|
|
394
|
+
const result = await client.listCustomers({
|
|
395
|
+
data_source_uuid: options.dataSource || config.getDefaultDataSource(),
|
|
396
|
+
status: options.status,
|
|
397
|
+
external_id: options.externalId,
|
|
398
|
+
page: options.page ? parseInt(options.page, 10) : void 0,
|
|
399
|
+
per_page: options.perPage ? parseInt(options.perPage, 10) : void 0
|
|
400
|
+
});
|
|
401
|
+
outputJson(result);
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
);
|
|
405
|
+
cmd.command("view").description("View a customer").argument("<uuid>", "Customer UUID").action(
|
|
406
|
+
withErrorHandling(async (uuid) => {
|
|
407
|
+
const customer = await client.getCustomer(uuid);
|
|
408
|
+
outputJson(customer);
|
|
409
|
+
})
|
|
410
|
+
);
|
|
411
|
+
cmd.command("search").description("Search customers by email").requiredOption("--email <email>", "Email address to search").action(
|
|
412
|
+
withErrorHandling(async (options) => {
|
|
413
|
+
const result = await client.searchCustomers(options.email);
|
|
414
|
+
outputJson(result.entries);
|
|
415
|
+
})
|
|
416
|
+
);
|
|
417
|
+
cmd.command("activities").description("List customer activities").argument("<uuid>", "Customer UUID").option("--page <number>", "Page number").option("--per-page <number>", "Results per page").action(
|
|
418
|
+
withErrorHandling(async (uuid, options) => {
|
|
419
|
+
const result = await client.getCustomerActivities(uuid, {
|
|
420
|
+
page: options.page ? parseInt(options.page, 10) : void 0,
|
|
421
|
+
per_page: options.perPage ? parseInt(options.perPage, 10) : void 0
|
|
422
|
+
});
|
|
423
|
+
outputJson(result);
|
|
424
|
+
})
|
|
425
|
+
);
|
|
426
|
+
cmd.command("subscriptions").description("List customer subscriptions").argument("<uuid>", "Customer UUID").action(
|
|
427
|
+
withErrorHandling(async (uuid) => {
|
|
428
|
+
const result = await client.getCustomerSubscriptions(uuid);
|
|
429
|
+
outputJson(result.entries);
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
return cmd;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/commands/plans.ts
|
|
436
|
+
import { Command as Command5 } from "commander";
|
|
437
|
+
function createPlansCommand() {
|
|
438
|
+
const cmd = new Command5("plans").description("Plan queries");
|
|
439
|
+
cmd.command("list").description("List plans").option("--data-source <uuid>", "Filter by data source UUID").option("--page <number>", "Page number").option("--per-page <number>", "Results per page").action(
|
|
440
|
+
withErrorHandling(
|
|
441
|
+
async (options) => {
|
|
442
|
+
const result = await client.listPlans({
|
|
443
|
+
data_source_uuid: options.dataSource || config.getDefaultDataSource(),
|
|
444
|
+
page: options.page ? parseInt(options.page, 10) : void 0,
|
|
445
|
+
per_page: options.perPage ? parseInt(options.perPage, 10) : void 0
|
|
446
|
+
});
|
|
447
|
+
outputJson(result);
|
|
448
|
+
}
|
|
449
|
+
)
|
|
450
|
+
);
|
|
451
|
+
cmd.command("view").description("View a plan").argument("<uuid>", "Plan UUID").action(
|
|
452
|
+
withErrorHandling(async (uuid) => {
|
|
453
|
+
const plan = await client.getPlan(uuid);
|
|
454
|
+
outputJson(plan);
|
|
455
|
+
})
|
|
456
|
+
);
|
|
457
|
+
return cmd;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// src/commands/invoices.ts
|
|
461
|
+
import { Command as Command6 } from "commander";
|
|
462
|
+
function createInvoicesCommand() {
|
|
463
|
+
const cmd = new Command6("invoices").description("Invoice queries");
|
|
464
|
+
cmd.command("list").description("List invoices").option("--customer <uuid>", "Filter by customer UUID").option("--data-source <uuid>", "Filter by data source UUID").option("--external-id <id>", "Filter by external ID").option("--page <number>", "Page number").option("--per-page <number>", "Results per page").action(
|
|
465
|
+
withErrorHandling(
|
|
466
|
+
async (options) => {
|
|
467
|
+
const result = await client.listInvoices({
|
|
468
|
+
customer_uuid: options.customer,
|
|
469
|
+
data_source_uuid: options.dataSource || config.getDefaultDataSource(),
|
|
470
|
+
external_id: options.externalId,
|
|
471
|
+
page: options.page ? parseInt(options.page, 10) : void 0,
|
|
472
|
+
per_page: options.perPage ? parseInt(options.perPage, 10) : void 0
|
|
473
|
+
});
|
|
474
|
+
outputJson(result);
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
);
|
|
478
|
+
cmd.command("view").description("View an invoice").argument("<uuid>", "Invoice UUID").action(
|
|
479
|
+
withErrorHandling(async (uuid) => {
|
|
480
|
+
const invoice = await client.getInvoice(uuid);
|
|
481
|
+
outputJson(invoice);
|
|
482
|
+
})
|
|
483
|
+
);
|
|
484
|
+
return cmd;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/commands/metrics.ts
|
|
488
|
+
import { Command as Command7 } from "commander";
|
|
489
|
+
|
|
490
|
+
// src/lib/dates.ts
|
|
491
|
+
import dayjs from "dayjs";
|
|
492
|
+
function parseDate(input) {
|
|
493
|
+
const d = dayjs(input);
|
|
494
|
+
if (!d.isValid()) {
|
|
495
|
+
throw new ChartMogulCliError(`Invalid date: ${input}`, 400);
|
|
496
|
+
}
|
|
497
|
+
return d.format("YYYY-MM-DD");
|
|
498
|
+
}
|
|
499
|
+
function getDefaultDateRange() {
|
|
500
|
+
return {
|
|
501
|
+
startDate: dayjs().subtract(30, "day").format("YYYY-MM-DD"),
|
|
502
|
+
endDate: dayjs().format("YYYY-MM-DD")
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/commands/metrics.ts
|
|
507
|
+
function buildMetricParams(options) {
|
|
508
|
+
const defaults = getDefaultDateRange();
|
|
509
|
+
return {
|
|
510
|
+
"start-date": options.startDate ? parseDate(options.startDate) : defaults.startDate,
|
|
511
|
+
"end-date": options.endDate ? parseDate(options.endDate) : defaults.endDate,
|
|
512
|
+
interval: options.interval
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function createMetricsCommand() {
|
|
516
|
+
const cmd = new Command7("metrics").description("Metrics and analytics");
|
|
517
|
+
cmd.command("all").description("Get all key metrics").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
518
|
+
withErrorHandling(async (options) => {
|
|
519
|
+
const result = await client.getAllMetrics(buildMetricParams(options));
|
|
520
|
+
outputJson(result);
|
|
521
|
+
})
|
|
522
|
+
);
|
|
523
|
+
cmd.command("mrr").description("Get Monthly Recurring Revenue").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
524
|
+
withErrorHandling(async (options) => {
|
|
525
|
+
const result = await client.getMrr(buildMetricParams(options));
|
|
526
|
+
outputJson(result);
|
|
527
|
+
})
|
|
528
|
+
);
|
|
529
|
+
cmd.command("arr").description("Get Annual Recurring Revenue").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
530
|
+
withErrorHandling(async (options) => {
|
|
531
|
+
const result = await client.getArr(buildMetricParams(options));
|
|
532
|
+
outputJson(result);
|
|
533
|
+
})
|
|
534
|
+
);
|
|
535
|
+
cmd.command("arpa").description("Get Average Revenue Per Account").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
536
|
+
withErrorHandling(async (options) => {
|
|
537
|
+
const result = await client.getArpa(buildMetricParams(options));
|
|
538
|
+
outputJson(result);
|
|
539
|
+
})
|
|
540
|
+
);
|
|
541
|
+
cmd.command("asp").description("Get Average Sale Price").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
542
|
+
withErrorHandling(async (options) => {
|
|
543
|
+
const result = await client.getAsp(buildMetricParams(options));
|
|
544
|
+
outputJson(result);
|
|
545
|
+
})
|
|
546
|
+
);
|
|
547
|
+
cmd.command("customer-count").description("Get customer count over time").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
548
|
+
withErrorHandling(async (options) => {
|
|
549
|
+
const result = await client.getCustomerCount(buildMetricParams(options));
|
|
550
|
+
outputJson(result);
|
|
551
|
+
})
|
|
552
|
+
);
|
|
553
|
+
cmd.command("customer-churn").description("Get customer churn rate").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
554
|
+
withErrorHandling(async (options) => {
|
|
555
|
+
const result = await client.getCustomerChurnRate(buildMetricParams(options));
|
|
556
|
+
outputJson(result);
|
|
557
|
+
})
|
|
558
|
+
);
|
|
559
|
+
cmd.command("mrr-churn").description("Get MRR churn rate").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
560
|
+
withErrorHandling(async (options) => {
|
|
561
|
+
const result = await client.getMrrChurnRate(buildMetricParams(options));
|
|
562
|
+
outputJson(result);
|
|
563
|
+
})
|
|
564
|
+
);
|
|
565
|
+
cmd.command("ltv").description("Get Customer Lifetime Value").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--interval <interval>", "Interval (day, week, month, quarter)").action(
|
|
566
|
+
withErrorHandling(async (options) => {
|
|
567
|
+
const result = await client.getLtv(buildMetricParams(options));
|
|
568
|
+
outputJson(result);
|
|
569
|
+
})
|
|
570
|
+
);
|
|
571
|
+
return cmd;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// src/commands/activities.ts
|
|
575
|
+
import { Command as Command8 } from "commander";
|
|
576
|
+
function createActivitiesCommand() {
|
|
577
|
+
const cmd = new Command8("activities").description("Activity operations");
|
|
578
|
+
cmd.command("list").description("List activities").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--type <type>", "Activity type (new_biz, expansion, contraction, churn, reactivation)").option("--page <number>", "Page number").option("--per-page <number>", "Results per page").action(
|
|
579
|
+
withErrorHandling(
|
|
580
|
+
async (options) => {
|
|
581
|
+
const result = await client.listActivities({
|
|
582
|
+
"start-date": options.startDate,
|
|
583
|
+
"end-date": options.endDate,
|
|
584
|
+
type: options.type,
|
|
585
|
+
page: options.page ? parseInt(options.page, 10) : void 0,
|
|
586
|
+
per_page: options.perPage ? parseInt(options.perPage, 10) : void 0
|
|
587
|
+
});
|
|
588
|
+
outputJson(result);
|
|
589
|
+
}
|
|
590
|
+
)
|
|
591
|
+
);
|
|
592
|
+
return cmd;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// src/cli.ts
|
|
596
|
+
var version = true ? "1.0.0" : "0.0.0-dev";
|
|
597
|
+
var program = new Command9();
|
|
598
|
+
program.name("chartmogul").description("A command-line interface for ChartMogul analytics").version(version).option("-c, --compact", "Minified JSON output (single line)").hook("preAction", (thisCommand) => {
|
|
599
|
+
const options = thisCommand.opts();
|
|
600
|
+
setOutputOptions({
|
|
601
|
+
compact: options.compact
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
program.addCommand(createAuthCommand());
|
|
605
|
+
program.addCommand(createAccountCommand());
|
|
606
|
+
program.addCommand(createDataSourcesCommand());
|
|
607
|
+
program.addCommand(createCustomersCommand());
|
|
608
|
+
program.addCommand(createPlansCommand());
|
|
609
|
+
program.addCommand(createInvoicesCommand());
|
|
610
|
+
program.addCommand(createMetricsCommand());
|
|
611
|
+
program.addCommand(createActivitiesCommand());
|
|
612
|
+
program.parseAsync().catch(() => {
|
|
613
|
+
process.exit(1);
|
|
614
|
+
});
|
|
615
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/lib/errors.ts","../src/lib/api-client.ts","../src/lib/command-utils.ts","../src/commands/account.ts","../src/commands/data-sources.ts","../src/commands/customers.ts","../src/commands/plans.ts","../src/commands/invoices.ts","../src/commands/metrics.ts","../src/lib/dates.ts","../src/commands/activities.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createAccountCommand } from './commands/account.js';\nimport { createDataSourcesCommand } from './commands/data-sources.js';\nimport { createCustomersCommand } from './commands/customers.js';\nimport { createPlansCommand } from './commands/plans.js';\nimport { createInvoicesCommand } from './commands/invoices.js';\nimport { createMetricsCommand } from './commands/metrics.js';\nimport { createActivitiesCommand } from './commands/activities.js';\n\ndeclare const __VERSION__: string | undefined;\n\nconst version = typeof __VERSION__ !== 'undefined' ? __VERSION__ : '0.0.0-dev';\n\nconst program = new Command();\n\nprogram\n .name('chartmogul')\n .description('A command-line interface for ChartMogul analytics')\n .version(version)\n .option('-c, --compact', 'Minified JSON output (single line)')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createAccountCommand());\nprogram.addCommand(createDataSourcesCommand());\nprogram.addCommand(createCustomersCommand());\nprogram.addCommand(createPlansCommand());\nprogram.addCommand(createInvoicesCommand());\nprogram.addCommand(createMetricsCommand());\nprogram.addCommand(createActivitiesCommand());\n\nprogram.parseAsync().catch(() => {\n process.exit(1);\n});\n","import type { OutputOptions } from '../types/index.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const mergedOptions = { ...globalOutputOptions, ...options };\n\n const jsonString = mergedOptions.compact ? JSON.stringify(data) : JSON.stringify(data, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication operations');\n\n cmd\n .command('login')\n .description('Configure ChartMogul API credentials')\n .requiredOption('--api-key <key>', 'ChartMogul API Key')\n .action(\n withErrorHandling(async (options: { apiKey: string }) => {\n auth.setApiKey(options.apiKey);\n await client.ping();\n outputJson({ message: 'Successfully authenticated with ChartMogul' });\n })\n );\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(\n withErrorHandling(async () => {\n auth.logout();\n outputJson({ message: 'Logged out successfully' });\n })\n );\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(\n withErrorHandling(async () => {\n outputJson({ authenticated: auth.isAuthenticated() });\n })\n );\n\n return cmd;\n}\n","import { Entry } from '@napi-rs/keyring';\nimport { config } from './config.js';\n\nconst SERVICE_NAME = 'chartmogul-cli';\nconst API_KEY_ACCOUNT = 'api-key';\n\nconst KEYRING_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: bun install -g @stephendolan/chartmogul-cli\\n' +\n 'Alternatively, use CHARTMOGUL_API_KEY environment variable.';\n\nfunction getKeyring(account: string): Entry | null {\n try {\n return new Entry(SERVICE_NAME, account);\n } catch {\n return null;\n }\n}\n\nfunction getPassword(account: string): string | null {\n const entry = getKeyring(account);\n if (entry) {\n try {\n return entry.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction setPassword(account: string, value: string): void {\n const entry = getKeyring(account);\n if (!entry) {\n throw new Error(KEYRING_UNAVAILABLE_ERROR);\n }\n entry.setPassword(value);\n}\n\nfunction deletePassword(account: string): boolean {\n const entry = getKeyring(account);\n if (entry) {\n return entry.deletePassword();\n }\n return false;\n}\n\nexport class AuthManager {\n getApiKey(): string | null {\n return getPassword(API_KEY_ACCOUNT) || process.env.CHARTMOGUL_API_KEY || null;\n }\n\n setApiKey(apiKey: string): void {\n setPassword(API_KEY_ACCOUNT, apiKey);\n }\n\n isAuthenticated(): boolean {\n return this.getApiKey() !== null;\n }\n\n logout(): void {\n deletePassword(API_KEY_ACCOUNT);\n config.clearDefaultDataSource();\n }\n}\n\nexport const auth = new AuthManager();\n","import Conf from 'conf';\n\ninterface ConfigSchema {\n defaultDataSource?: string;\n}\n\nconst store = new Conf<ConfigSchema>({\n projectName: 'chartmogul-cli',\n});\n\nexport const config = {\n getDefaultDataSource(): string | undefined {\n return store.get('defaultDataSource') || process.env.CHARTMOGUL_DATA_SOURCE;\n },\n\n setDefaultDataSource(dataSourceUuid: string): void {\n store.set('defaultDataSource', dataSourceUuid);\n },\n\n clearDefaultDataSource(): void {\n store.delete('defaultDataSource');\n },\n\n clear(): void {\n store.clear();\n },\n};\n","import type { ChartMogulError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class ChartMogulCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = 'ChartMogulCliError';\n }\n}\n\nexport class ChartMogulApiError extends Error {\n constructor(\n message: string,\n public apiError: unknown,\n public statusCode: number\n ) {\n super(message);\n this.name = 'ChartMogulApiError';\n }\n}\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /api[_-]?key[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*basic\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface ApiErrorResponse {\n error?: string;\n message?: string;\n errors?: Array<{\n key?: string;\n message?: string;\n }>;\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): ChartMogulError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n };\n }\n\n const apiError = error as ApiErrorResponse;\n\n let detail = 'An error occurred';\n if (apiError.message) {\n detail = apiError.message;\n } else if (apiError.errors?.length) {\n detail = apiError.errors\n .map((e) => e.message || e.key)\n .filter(Boolean)\n .join('; ');\n }\n\n return {\n name: apiError.error || 'api_error',\n detail: sanitizeErrorMessage(detail),\n };\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const hint =\n name === 'too_many_requests'\n ? 'ChartMogul API rate limit exceeded. Wait a moment and retry.'\n : undefined;\n\n const response: { error: { name: string; detail: string; statusCode: number }; hint?: string } = {\n error: { name, detail, statusCode },\n };\n\n if (hint) {\n response.hint = hint;\n }\n\n outputJson(response);\n process.exit(1);\n}\n\nexport function handleChartMogulError(error: unknown): never {\n if (error instanceof ChartMogulCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n if (error instanceof ChartMogulApiError) {\n const cmError = sanitizeApiError(error.apiError);\n formatErrorResponse(cmError.name, cmError.detail, error.statusCode);\n }\n\n if (error instanceof Error) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('unknown_error', sanitized, 1);\n }\n\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n}\n","import { auth } from './auth.js';\nimport { ChartMogulCliError, ChartMogulApiError } from './errors.js';\nimport type {\n Account,\n DataSource,\n Customer,\n Plan,\n Subscription,\n Invoice,\n MetricsResponse,\n Activity,\n CustomerListResponse,\n PaginatedResponse,\n} from '../types/index.js';\n\nconst API_BASE = 'https://api.chartmogul.com/v1';\n\nexport class ChartMogulClient {\n private getAuthHeader(): string {\n const apiKey = auth.getApiKey();\n if (!apiKey) {\n throw new ChartMogulCliError('Not authenticated. Please run: chartmogul auth login', 401);\n }\n return `Basic ${Buffer.from(`${apiKey}:`).toString('base64')}`;\n }\n\n private async request<T>(\n method: string,\n path: string,\n options: {\n params?: Record<string, string | number | boolean | undefined>;\n body?: unknown;\n } = {}\n ): Promise<T> {\n const { params, body } = options;\n\n const url = new URL(`${API_BASE}${path}`);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n\n const authHeader = this.getAuthHeader();\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: authHeader,\n 'Content-Type': 'application/json',\n },\n };\n if (body) {\n fetchOptions.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url.toString(), fetchOptions);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown network error';\n throw new ChartMogulCliError(`Network request failed: ${message}`, 0);\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get('Retry-After') || '60';\n throw new ChartMogulCliError(\n `Rate limited by ChartMogul API. Retry after ${retryAfter} seconds.`,\n 429\n );\n }\n\n if (response.status === 204) {\n return {} as T;\n }\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new ChartMogulApiError('API request failed', error, response.status);\n }\n\n return response.json() as Promise<T>;\n }\n\n async getAccount() {\n return this.request<Account>('GET', '/account');\n }\n\n async ping() {\n return this.request<{ data: string }>('GET', '/ping');\n }\n\n async listDataSources() {\n return this.request<{ data_sources: DataSource[] }>('GET', '/data_sources');\n }\n\n async getDataSource(uuid: string) {\n return this.request<DataSource>('GET', `/data_sources/${uuid}`);\n }\n\n async listCustomers(\n params: {\n data_source_uuid?: string;\n status?: string;\n system?: string;\n external_id?: string;\n page?: number;\n per_page?: number;\n } = {}\n ) {\n return this.request<CustomerListResponse>('GET', '/customers', { params });\n }\n\n async getCustomer(uuid: string) {\n return this.request<Customer>('GET', `/customers/${uuid}`);\n }\n\n async searchCustomers(email: string) {\n return this.request<{ entries: Customer[] }>('GET', '/customers/search', {\n params: { email },\n });\n }\n\n async getCustomerActivities(uuid: string, params: { page?: number; per_page?: number } = {}) {\n return this.request<PaginatedResponse<Activity>>('GET', `/customers/${uuid}/activities`, {\n params,\n });\n }\n\n async getCustomerSubscriptions(uuid: string) {\n return this.request<{ entries: Subscription[] }>('GET', `/customers/${uuid}/subscriptions`);\n }\n\n async listPlans(params: { data_source_uuid?: string; page?: number; per_page?: number } = {}) {\n return this.request<{ plans: Plan[]; has_more: boolean; per_page: number; page: number }>(\n 'GET',\n '/plans',\n { params }\n );\n }\n\n async getPlan(uuid: string) {\n return this.request<Plan>('GET', `/plans/${uuid}`);\n }\n\n async listInvoices(\n params: {\n customer_uuid?: string;\n data_source_uuid?: string;\n external_id?: string;\n page?: number;\n per_page?: number;\n } = {}\n ) {\n return this.request<{ invoices: Invoice[]; has_more: boolean }>('GET', '/invoices', { params });\n }\n\n async getInvoice(uuid: string) {\n return this.request<Invoice>('GET', `/invoices/${uuid}`);\n }\n\n async getMrr(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/mrr', { params });\n }\n\n async getArr(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/arr', { params });\n }\n\n async getArpa(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/arpa', { params });\n }\n\n async getAsp(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/asp', { params });\n }\n\n async getCustomerCount(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/customer-count', { params });\n }\n\n async getCustomerChurnRate(params: {\n 'start-date': string;\n 'end-date': string;\n interval?: string;\n }) {\n return this.request<MetricsResponse>('GET', '/metrics/customer-churn-rate', { params });\n }\n\n async getMrrChurnRate(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/mrr-churn-rate', { params });\n }\n\n async getLtv(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/ltv', { params });\n }\n\n async getAllMetrics(params: { 'start-date': string; 'end-date': string; interval?: string }) {\n return this.request<MetricsResponse>('GET', '/metrics/all', { params });\n }\n\n async listActivities(\n params: {\n 'start-date'?: string;\n 'end-date'?: string;\n type?: string;\n page?: number;\n per_page?: number;\n } = {}\n ) {\n return this.request<PaginatedResponse<Activity>>('GET', '/activities', { params });\n }\n}\n\nexport const client = new ChartMogulClient();\n","import { handleChartMogulError } from './errors.js';\n\nexport function withErrorHandling<T extends unknown[], R>(\n fn: (...args: T) => Promise<R>\n): (...args: T) => Promise<void> {\n return async (...args: T) => {\n try {\n await fn(...args);\n } catch (error) {\n handleChartMogulError(error);\n }\n };\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createAccountCommand(): Command {\n const cmd = new Command('account').description('Account operations');\n\n cmd\n .command('view')\n .description('View account details')\n .action(\n withErrorHandling(async () => {\n const account = await client.getAccount();\n outputJson(account);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createDataSourcesCommand(): Command {\n const cmd = new Command('data-sources').description('Data source operations');\n\n cmd\n .command('list')\n .description('List all data sources')\n .action(\n withErrorHandling(async () => {\n const result = await client.listDataSources();\n outputJson(result.data_sources);\n })\n );\n\n cmd\n .command('view')\n .description('View a data source')\n .argument('<uuid>', 'Data source UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n const dataSource = await client.getDataSource(uuid);\n outputJson(dataSource);\n })\n );\n\n cmd\n .command('set-default')\n .description('Set default data source for filtering')\n .argument('<uuid>', 'Data source UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n config.setDefaultDataSource(uuid);\n outputJson({ message: `Default data source set to ${uuid}` });\n })\n );\n\n cmd\n .command('get-default')\n .description('Get default data source')\n .action(\n withErrorHandling(async () => {\n const defaultDs = config.getDefaultDataSource();\n outputJson({ default_data_source: defaultDs || null });\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createCustomersCommand(): Command {\n const cmd = new Command('customers').description('Customer queries');\n\n cmd\n .command('list')\n .description('List customers')\n .option('--data-source <uuid>', 'Filter by data source UUID')\n .option('--status <status>', 'Filter by status (Lead, Active, Cancelled)')\n .option('--external-id <id>', 'Filter by external ID')\n .option('--page <number>', 'Page number')\n .option('--per-page <number>', 'Results per page (max 200)')\n .action(\n withErrorHandling(\n async (options: {\n dataSource?: string;\n status?: string;\n externalId?: string;\n page?: string;\n perPage?: string;\n }) => {\n const result = await client.listCustomers({\n data_source_uuid: options.dataSource || config.getDefaultDataSource(),\n status: options.status,\n external_id: options.externalId,\n page: options.page ? parseInt(options.page, 10) : undefined,\n per_page: options.perPage ? parseInt(options.perPage, 10) : undefined,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View a customer')\n .argument('<uuid>', 'Customer UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n const customer = await client.getCustomer(uuid);\n outputJson(customer);\n })\n );\n\n cmd\n .command('search')\n .description('Search customers by email')\n .requiredOption('--email <email>', 'Email address to search')\n .action(\n withErrorHandling(async (options: { email: string }) => {\n const result = await client.searchCustomers(options.email);\n outputJson(result.entries);\n })\n );\n\n cmd\n .command('activities')\n .description('List customer activities')\n .argument('<uuid>', 'Customer UUID')\n .option('--page <number>', 'Page number')\n .option('--per-page <number>', 'Results per page')\n .action(\n withErrorHandling(async (uuid: string, options: { page?: string; perPage?: string }) => {\n const result = await client.getCustomerActivities(uuid, {\n page: options.page ? parseInt(options.page, 10) : undefined,\n per_page: options.perPage ? parseInt(options.perPage, 10) : undefined,\n });\n outputJson(result);\n })\n );\n\n cmd\n .command('subscriptions')\n .description('List customer subscriptions')\n .argument('<uuid>', 'Customer UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n const result = await client.getCustomerSubscriptions(uuid);\n outputJson(result.entries);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createPlansCommand(): Command {\n const cmd = new Command('plans').description('Plan queries');\n\n cmd\n .command('list')\n .description('List plans')\n .option('--data-source <uuid>', 'Filter by data source UUID')\n .option('--page <number>', 'Page number')\n .option('--per-page <number>', 'Results per page')\n .action(\n withErrorHandling(\n async (options: { dataSource?: string; page?: string; perPage?: string }) => {\n const result = await client.listPlans({\n data_source_uuid: options.dataSource || config.getDefaultDataSource(),\n page: options.page ? parseInt(options.page, 10) : undefined,\n per_page: options.perPage ? parseInt(options.perPage, 10) : undefined,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View a plan')\n .argument('<uuid>', 'Plan UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n const plan = await client.getPlan(uuid);\n outputJson(plan);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createInvoicesCommand(): Command {\n const cmd = new Command('invoices').description('Invoice queries');\n\n cmd\n .command('list')\n .description('List invoices')\n .option('--customer <uuid>', 'Filter by customer UUID')\n .option('--data-source <uuid>', 'Filter by data source UUID')\n .option('--external-id <id>', 'Filter by external ID')\n .option('--page <number>', 'Page number')\n .option('--per-page <number>', 'Results per page')\n .action(\n withErrorHandling(\n async (options: {\n customer?: string;\n dataSource?: string;\n externalId?: string;\n page?: string;\n perPage?: string;\n }) => {\n const result = await client.listInvoices({\n customer_uuid: options.customer,\n data_source_uuid: options.dataSource || config.getDefaultDataSource(),\n external_id: options.externalId,\n page: options.page ? parseInt(options.page, 10) : undefined,\n per_page: options.perPage ? parseInt(options.perPage, 10) : undefined,\n });\n outputJson(result);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View an invoice')\n .argument('<uuid>', 'Invoice UUID')\n .action(\n withErrorHandling(async (uuid: string) => {\n const invoice = await client.getInvoice(uuid);\n outputJson(invoice);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { getDefaultDateRange, parseDate } from '../lib/dates.js';\n\ninterface MetricOptions {\n startDate?: string;\n endDate?: string;\n interval?: string;\n}\n\nfunction buildMetricParams(options: MetricOptions) {\n const defaults = getDefaultDateRange();\n return {\n 'start-date': options.startDate ? parseDate(options.startDate) : defaults.startDate,\n 'end-date': options.endDate ? parseDate(options.endDate) : defaults.endDate,\n interval: options.interval,\n };\n}\n\nexport function createMetricsCommand(): Command {\n const cmd = new Command('metrics').description('Metrics and analytics');\n\n cmd\n .command('all')\n .description('Get all key metrics')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getAllMetrics(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('mrr')\n .description('Get Monthly Recurring Revenue')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getMrr(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('arr')\n .description('Get Annual Recurring Revenue')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getArr(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('arpa')\n .description('Get Average Revenue Per Account')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getArpa(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('asp')\n .description('Get Average Sale Price')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getAsp(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('customer-count')\n .description('Get customer count over time')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getCustomerCount(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('customer-churn')\n .description('Get customer churn rate')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getCustomerChurnRate(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('mrr-churn')\n .description('Get MRR churn rate')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getMrrChurnRate(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n cmd\n .command('ltv')\n .description('Get Customer Lifetime Value')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--interval <interval>', 'Interval (day, week, month, quarter)')\n .action(\n withErrorHandling(async (options: MetricOptions) => {\n const result = await client.getLtv(buildMetricParams(options));\n outputJson(result);\n })\n );\n\n return cmd;\n}\n","import dayjs from 'dayjs';\nimport { ChartMogulCliError } from './errors.js';\n\nexport function parseDate(input: string): string {\n const d = dayjs(input);\n if (!d.isValid()) {\n throw new ChartMogulCliError(`Invalid date: ${input}`, 400);\n }\n return d.format('YYYY-MM-DD');\n}\n\nexport function getDefaultDateRange(): { startDate: string; endDate: string } {\n return {\n startDate: dayjs().subtract(30, 'day').format('YYYY-MM-DD'),\n endDate: dayjs().format('YYYY-MM-DD'),\n };\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createActivitiesCommand(): Command {\n const cmd = new Command('activities').description('Activity operations');\n\n cmd\n .command('list')\n .description('List activities')\n .option('--start-date <date>', 'Start date (YYYY-MM-DD)')\n .option('--end-date <date>', 'End date (YYYY-MM-DD)')\n .option('--type <type>', 'Activity type (new_biz, expansion, contraction, churn, reactivation)')\n .option('--page <number>', 'Page number')\n .option('--per-page <number>', 'Results per page')\n .action(\n withErrorHandling(\n async (options: {\n startDate?: string;\n endDate?: string;\n type?: string;\n page?: string;\n perPage?: string;\n }) => {\n const result = await client.listActivities({\n 'start-date': options.startDate,\n 'end-date': options.endDate,\n type: options.type,\n page: options.page ? parseInt(options.page, 10) : undefined,\n per_page: options.perPage ? parseInt(options.perPage, 10) : undefined,\n });\n outputJson(result);\n }\n )\n );\n\n return cmd;\n}\n"],"mappings":"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","names":["Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stephendolan/chartmogul-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A command-line interface for ChartMogul analytics",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"chartmogul": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "bun run src/cli.ts",
|
|
12
|
+
"build": "bun run tsup",
|
|
13
|
+
"test": "bun run vitest",
|
|
14
|
+
"lint": "bun run oxlint src",
|
|
15
|
+
"format": "bun run biome format --write src",
|
|
16
|
+
"format:check": "bun run biome format src",
|
|
17
|
+
"typecheck": "bun run tsc --noEmit",
|
|
18
|
+
"link": "bun run build && bun link",
|
|
19
|
+
"start": "bun dist/cli.js",
|
|
20
|
+
"prepublishOnly": "bun run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"chartmogul",
|
|
24
|
+
"analytics",
|
|
25
|
+
"cli",
|
|
26
|
+
"revenue",
|
|
27
|
+
"mrr",
|
|
28
|
+
"arr",
|
|
29
|
+
"churn",
|
|
30
|
+
"subscription",
|
|
31
|
+
"saas",
|
|
32
|
+
"command-line",
|
|
33
|
+
"llm",
|
|
34
|
+
"ai-friendly"
|
|
35
|
+
],
|
|
36
|
+
"author": "Stephen Dolan <https://github.com/stephendolan>",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/stephendolan/chartmogul-cli.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/stephendolan/chartmogul-cli/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/stephendolan/chartmogul-cli#readme",
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE"
|
|
50
|
+
],
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@napi-rs/keyring": "^1.2.0",
|
|
53
|
+
"commander": "^12.0.0",
|
|
54
|
+
"conf": "^12.0.0",
|
|
55
|
+
"dayjs": "^1.11.19"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@biomejs/biome": "^1.9.4",
|
|
59
|
+
"@types/node": "^20.0.0",
|
|
60
|
+
"oxlint": "^0.16.0",
|
|
61
|
+
"tsup": "^8.0.0",
|
|
62
|
+
"tsx": "^4.7.0",
|
|
63
|
+
"typescript": "^5.3.0",
|
|
64
|
+
"vitest": "^4.0.4"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"bun": ">=1.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|