@ericdahl.dev/openai-and-claude-usage-report-generator 1.0.3
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/README.md +246 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +103 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +46 -0
- package/dist/index.test.js.map +1 -0
- package/dist/integration.test.d.ts +2 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +44 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/usage-report.d.ts +17 -0
- package/dist/usage-report.d.ts.map +1 -0
- package/dist/usage-report.js +359 -0
- package/dist/usage-report.js.map +1 -0
- package/dist/usage-report.test.d.ts +2 -0
- package/dist/usage-report.test.d.ts.map +1 -0
- package/dist/usage-report.test.js +630 -0
- package/dist/usage-report.test.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# OpenAI and Claude Usage Report Generator
|
|
2
|
+
|
|
3
|
+
A CLI tool and library for generating billing reports from the **OpenAI** or **Claude (Anthropic)** cost APIs. Outputs Markdown (readable) and CSV (data) reports.
|
|
4
|
+
|
|
5
|
+
Can be used as:
|
|
6
|
+
- **CLI tool**: Run reports from the command line
|
|
7
|
+
- **Library**: Import functions programmatically in your Node.js/TypeScript projects
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Fetches usage/cost data from OpenAI's organization costs API or Anthropic's [Usage and Cost API](https://platform.claude.com/docs/en/build-with-claude/usage-cost-api)
|
|
12
|
+
- Generates detailed Markdown reports with summaries and breakdowns
|
|
13
|
+
- Exports CSV data for further analysis
|
|
14
|
+
- Exports JSON data for programmatic consumption
|
|
15
|
+
- Daily and line-item cost breakdowns
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- Node.js 18+ and Yarn (`.nvmrc` specifies 22)
|
|
20
|
+
- **OpenAI**: **Admin API key** (not a standard API key), Organization ID, and Project ID
|
|
21
|
+
- ⚠️ **Important**: Standard API keys do not work. You need an admin key with organization access.
|
|
22
|
+
- Create one in [OpenAI Platform → Settings → Organization → API keys](https://platform.openai.com/api-keys)
|
|
23
|
+
- **Claude**: Anthropic **Admin API key** (`sk-ant-admin...`)
|
|
24
|
+
- ⚠️ **Important**: Standard API keys do not work. You need an admin key.
|
|
25
|
+
- Create one in [Console → Settings → Admin keys](https://console.anthropic.com/settings/admin-keys)
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
### As a CLI Tool (Development)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone <repository-url>
|
|
33
|
+
cd openai-and-claude-usage-report-generator
|
|
34
|
+
yarn install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### As an npm Package (Library)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
yarn add @ericdahl.dev/openai-and-claude-usage-report-generator
|
|
41
|
+
# or
|
|
42
|
+
npm install @ericdahl.dev/openai-and-claude-usage-report-generator
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
Create a `.env` file in the root directory (see `.env.example` for a template).
|
|
48
|
+
|
|
49
|
+
⚠️ **Important**: Both platforms require **admin/administrative API keys**. Standard API keys will not work.
|
|
50
|
+
|
|
51
|
+
**OpenAI** (default):
|
|
52
|
+
|
|
53
|
+
```env
|
|
54
|
+
OPENAI_ADMIN_KEY=sk-... # Must be an admin key, not a standard API key
|
|
55
|
+
OPENAI_ORG_ID=org-...
|
|
56
|
+
OPENAI_PROJECT_ID=proj_...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Claude**:
|
|
60
|
+
|
|
61
|
+
```env
|
|
62
|
+
ANTHROPIC_ADMIN_API_KEY=sk-ant-admin-... # Must be an admin key (starts with sk-ant-admin), not a standard API key
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### CLI Usage
|
|
68
|
+
|
|
69
|
+
Generate a report for a date range. Default provider is OpenAI.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
yarn report 2024-01-01 2024-01-31
|
|
73
|
+
yarn report 2024-01-01 2024-01-31 --provider openai
|
|
74
|
+
yarn report 2024-01-01 2024-01-31 --provider claude
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Library Usage
|
|
78
|
+
|
|
79
|
+
Import and use the functions programmatically in your code:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import {
|
|
83
|
+
fetchOpenAICosts,
|
|
84
|
+
fetchClaudeCosts,
|
|
85
|
+
aggregateCosts,
|
|
86
|
+
generateMarkdownReport,
|
|
87
|
+
generateCSVReport,
|
|
88
|
+
generateJSONReport,
|
|
89
|
+
writeReports,
|
|
90
|
+
parseDate,
|
|
91
|
+
validateDateRange,
|
|
92
|
+
loadConfig,
|
|
93
|
+
} from '@ericdahl.dev/openai-and-claude-usage-report-generator';
|
|
94
|
+
import type { OpenAIReportConfig, ClaudeReportConfig } from '@ericdahl.dev/openai-and-claude-usage-report-generator';
|
|
95
|
+
|
|
96
|
+
// Example: Fetch and process OpenAI costs
|
|
97
|
+
// Note: OPENAI_ADMIN_KEY must be an admin key, not a standard API key
|
|
98
|
+
async function generateOpenAIReport() {
|
|
99
|
+
const config: OpenAIReportConfig = {
|
|
100
|
+
provider: 'openai',
|
|
101
|
+
startDate: '2024-01-01',
|
|
102
|
+
endDate: '2024-01-31',
|
|
103
|
+
apiKey: process.env.OPENAI_ADMIN_KEY!, // Must be an admin key
|
|
104
|
+
orgId: process.env.OPENAI_ORG_ID!,
|
|
105
|
+
projectId: process.env.OPENAI_PROJECT_ID!,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Fetch cost data
|
|
109
|
+
const buckets = await fetchOpenAICosts(config);
|
|
110
|
+
|
|
111
|
+
// Aggregate the data
|
|
112
|
+
const aggregated = aggregateCosts(
|
|
113
|
+
buckets,
|
|
114
|
+
config.startDate,
|
|
115
|
+
config.endDate,
|
|
116
|
+
config.projectId
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Generate reports
|
|
120
|
+
const markdown = generateMarkdownReport(aggregated, config.orgId, 'openai');
|
|
121
|
+
const csv = generateCSVReport(aggregated);
|
|
122
|
+
const json = generateJSONReport(aggregated, config.orgId, 'openai');
|
|
123
|
+
|
|
124
|
+
// Or write directly to files
|
|
125
|
+
const { mdPath, csvPath, jsonPath } = writeReports(aggregated, config.orgId, 'openai');
|
|
126
|
+
|
|
127
|
+
console.log(`Reports written to ${mdPath}, ${csvPath}, and ${jsonPath}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Example: Fetch and process Claude costs
|
|
131
|
+
// Note: ANTHROPIC_ADMIN_API_KEY must be an admin key (sk-ant-admin...), not a standard API key
|
|
132
|
+
async function generateClaudeReport() {
|
|
133
|
+
const config: ClaudeReportConfig = {
|
|
134
|
+
provider: 'claude',
|
|
135
|
+
startDate: '2024-01-01',
|
|
136
|
+
endDate: '2024-01-31',
|
|
137
|
+
apiKey: process.env.ANTHROPIC_ADMIN_API_KEY!, // Must be an admin key (starts with sk-ant-admin)
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const buckets = await fetchClaudeCosts(config);
|
|
141
|
+
const aggregated = aggregateCosts(buckets, config.startDate, config.endDate, 'default');
|
|
142
|
+
const markdown = generateMarkdownReport(aggregated, 'default', 'claude');
|
|
143
|
+
|
|
144
|
+
console.log(markdown);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Note**: When using as a library, you need to handle environment variables yourself. The `loadConfig` function is available but requires environment variables to be set, or you can construct the config objects directly as shown above.
|
|
149
|
+
|
|
150
|
+
⚠️ **Important Reminder**: Both platforms require **admin/administrative API keys**. Standard API keys will not work for accessing cost/usage data.
|
|
151
|
+
|
|
152
|
+
## Output
|
|
153
|
+
|
|
154
|
+
- **OpenAI**: `reports/openai/`
|
|
155
|
+
- **Claude**: `reports/claude/`
|
|
156
|
+
|
|
157
|
+
Each run produces:
|
|
158
|
+
|
|
159
|
+
- `usage-YYYY-MM-DD-to-YYYY-MM-DD.md` – Human-readable Markdown report
|
|
160
|
+
- `usage-YYYY-MM-DD-to-YYYY-MM-DD.csv` – CSV data export
|
|
161
|
+
- `usage-YYYY-MM-DD-to-YYYY-MM-DD.json` – JSON data export for programmatic consumption
|
|
162
|
+
|
|
163
|
+
## Report Contents
|
|
164
|
+
|
|
165
|
+
The Markdown report includes:
|
|
166
|
+
|
|
167
|
+
- **Summary**: Total cost, billing days, average daily cost
|
|
168
|
+
- **Cost by Model/Service**: Breakdown by line item with percentages
|
|
169
|
+
- **Daily Usage Breakdown**: Detailed daily costs by model/service
|
|
170
|
+
- **Total by Day**: Daily totals for quick overview
|
|
171
|
+
|
|
172
|
+
The CSV export contains:
|
|
173
|
+
- Date, line item, cost (USD), and project ID for each entry
|
|
174
|
+
|
|
175
|
+
The JSON export contains:
|
|
176
|
+
- Metadata (provider, billing period, project/organization IDs, generation timestamp)
|
|
177
|
+
- Summary (total cost, billing days, average daily cost)
|
|
178
|
+
- Costs by line item (sorted by cost, includes percentages)
|
|
179
|
+
- Daily breakdown (all daily costs by date and line item)
|
|
180
|
+
- Daily totals (aggregated totals per day)
|
|
181
|
+
|
|
182
|
+
## API Reference
|
|
183
|
+
|
|
184
|
+
### Core Functions
|
|
185
|
+
|
|
186
|
+
#### `fetchOpenAICosts(config: OpenAIReportConfig): Promise<CostBucket[]>`
|
|
187
|
+
Fetches cost data from OpenAI's organization costs API. Returns an array of cost buckets.
|
|
188
|
+
|
|
189
|
+
#### `fetchClaudeCosts(config: ClaudeReportConfig): Promise<CostBucket[]>`
|
|
190
|
+
Fetches cost data from Anthropic's cost report API. Returns an array of cost buckets (normalized to match OpenAI format).
|
|
191
|
+
|
|
192
|
+
#### `aggregateCosts(buckets: CostBucket[], startDate: string, endDate: string, projectId: string): AggregatedCosts`
|
|
193
|
+
Aggregates cost buckets into a structured format with totals, daily breakdowns, and line item summaries.
|
|
194
|
+
|
|
195
|
+
#### `generateMarkdownReport(aggregated: AggregatedCosts, orgId: string, provider: 'openai' | 'claude'): string`
|
|
196
|
+
Generates a human-readable Markdown report from aggregated costs.
|
|
197
|
+
|
|
198
|
+
#### `generateCSVReport(aggregated: AggregatedCosts): string`
|
|
199
|
+
Generates a CSV report from aggregated costs.
|
|
200
|
+
|
|
201
|
+
#### `generateJSONReport(aggregated: AggregatedCosts, orgId: string, provider: 'openai' | 'claude'): string`
|
|
202
|
+
Generates a JSON report from aggregated costs. Returns a formatted JSON string with metadata, summary, costs by line item, daily breakdown, and daily totals.
|
|
203
|
+
|
|
204
|
+
#### `writeReports(aggregated: AggregatedCosts, orgId: string, provider: Provider, baseDir?: string): { mdPath: string; csvPath: string; jsonPath: string }`
|
|
205
|
+
Writes Markdown, CSV, and JSON reports to disk. Returns paths to the generated files.
|
|
206
|
+
|
|
207
|
+
### Utility Functions
|
|
208
|
+
|
|
209
|
+
#### `parseDate(dateStr: string): Date`
|
|
210
|
+
Parses a date string in YYYY-MM-DD format and returns a Date object.
|
|
211
|
+
|
|
212
|
+
#### `validateDateRange(start: Date, end: Date): void`
|
|
213
|
+
Validates that the end date is after the start date. Throws an error if invalid.
|
|
214
|
+
|
|
215
|
+
#### `loadConfig(startDate: string, endDate: string, provider: Provider): ReportConfig`
|
|
216
|
+
Loads configuration from environment variables. Requires appropriate env vars to be set based on provider.
|
|
217
|
+
|
|
218
|
+
### Types
|
|
219
|
+
|
|
220
|
+
All TypeScript types are exported. Key types include:
|
|
221
|
+
- `OpenAIReportConfig` - Configuration for OpenAI API
|
|
222
|
+
- `ClaudeReportConfig` - Configuration for Claude API
|
|
223
|
+
- `AggregatedCosts` - Aggregated cost data structure
|
|
224
|
+
- `CostBucket` - Individual cost bucket from API
|
|
225
|
+
- `DailyCost` - Daily cost entry
|
|
226
|
+
- `Provider` - Union type: `'openai' | 'claude'`
|
|
227
|
+
|
|
228
|
+
## Development
|
|
229
|
+
|
|
230
|
+
### Running Tests
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
yarn test # watch mode
|
|
234
|
+
yarn test:run # single run (used by CI)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Building
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
yarn build
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### CI
|
|
244
|
+
|
|
245
|
+
GitHub Actions runs on push and pull requests to `main`: `yarn install --frozen-lockfile`, `yarn test:run`, then `yarn build`. See [.github/workflows/ci.yml](.github/workflows/ci.yml).
|
|
246
|
+
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* CLI Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Command-line interface for generating usage reports.
|
|
6
|
+
* Imports functionality from the library entry point.
|
|
7
|
+
*
|
|
8
|
+
* Usage: yarn report YYYY-MM-DD YYYY-MM-DD [--provider openai|claude]
|
|
9
|
+
*/
|
|
10
|
+
import 'dotenv/config';
|
|
11
|
+
import { type Provider } from './index.js';
|
|
12
|
+
export declare function parseArguments(): {
|
|
13
|
+
startDate: string;
|
|
14
|
+
endDate: string;
|
|
15
|
+
provider: Provider;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAEH,OAAO,eAAe,CAAC;AACvB,OAAO,EASL,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAOpB,wBAAgB,cAAc,IAAI;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAyB3F"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Command-line interface for generating usage reports.
|
|
6
|
+
* Imports functionality from the library entry point.
|
|
7
|
+
*
|
|
8
|
+
* Usage: yarn report YYYY-MM-DD YYYY-MM-DD [--provider openai|claude]
|
|
9
|
+
*/
|
|
10
|
+
import 'dotenv/config';
|
|
11
|
+
import { fetchOpenAICosts, fetchClaudeCosts, aggregateCosts, writeReports, loadConfig, parseDate, validateDateRange, } from './index.js';
|
|
12
|
+
const USAGE = 'Usage: yarn report YYYY-MM-DD YYYY-MM-DD [--provider openai|claude]\n' +
|
|
13
|
+
'Example: yarn report 2024-01-01 2024-01-31\n' +
|
|
14
|
+
'Example: yarn report 2024-01-01 2024-01-31 --provider claude';
|
|
15
|
+
export function parseArguments() {
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const providerIdx = args.indexOf('--provider');
|
|
18
|
+
const providerArg = providerIdx >= 0 && args[providerIdx + 1] != null ? args[providerIdx + 1] : null;
|
|
19
|
+
const filtered = providerIdx < 0
|
|
20
|
+
? args
|
|
21
|
+
: args.filter((_, i) => i !== providerIdx && i !== providerIdx + 1);
|
|
22
|
+
if (filtered.length !== 2) {
|
|
23
|
+
throw new Error(`Invalid arguments\n${USAGE}`);
|
|
24
|
+
}
|
|
25
|
+
const provider = providerArg === 'claude' ? 'claude' : providerArg === 'openai' ? 'openai' : 'openai';
|
|
26
|
+
if (providerArg != null && providerArg !== 'openai' && providerArg !== 'claude') {
|
|
27
|
+
throw new Error(`Invalid --provider: ${providerArg}. Use openai or claude.\n${USAGE}`);
|
|
28
|
+
}
|
|
29
|
+
const [startDate, endDate] = filtered;
|
|
30
|
+
const start = parseDate(startDate);
|
|
31
|
+
const end = parseDate(endDate);
|
|
32
|
+
validateDateRange(start, end);
|
|
33
|
+
return { startDate, endDate, provider };
|
|
34
|
+
}
|
|
35
|
+
function displayTerminalSummary(aggregated, mdPath, csvPath, jsonPath, provider) {
|
|
36
|
+
const title = provider === 'claude' ? 'Claude API Usage Report' : 'OpenAI API Usage Report';
|
|
37
|
+
console.log(title);
|
|
38
|
+
console.log('=======================');
|
|
39
|
+
console.log(`Period: ${aggregated.startDate} to ${aggregated.endDate}`);
|
|
40
|
+
console.log(`Project: ${aggregated.projectId}\n`);
|
|
41
|
+
console.log(`Total Cost: $${aggregated.totalCost.toFixed(2)} USD`);
|
|
42
|
+
console.log(`Total Days: ${aggregated.billingDays}`);
|
|
43
|
+
console.log(`Average Daily Cost: $${aggregated.averageDailyCost.toFixed(2)}\n`);
|
|
44
|
+
if (aggregated.costsByLineItem.size > 0) {
|
|
45
|
+
console.log('Top Models/Services:');
|
|
46
|
+
const sortedLineItems = Array.from(aggregated.costsByLineItem.entries())
|
|
47
|
+
.sort((a, b) => b[1] - a[1])
|
|
48
|
+
.slice(0, 5);
|
|
49
|
+
for (const [lineItem, cost] of sortedLineItems) {
|
|
50
|
+
console.log(` ${lineItem}: $${cost.toFixed(2)}`);
|
|
51
|
+
}
|
|
52
|
+
console.log('');
|
|
53
|
+
}
|
|
54
|
+
console.log('Reports generated:');
|
|
55
|
+
console.log(` - ${mdPath}`);
|
|
56
|
+
console.log(` - ${csvPath}`);
|
|
57
|
+
console.log(` - ${jsonPath}`);
|
|
58
|
+
}
|
|
59
|
+
async function main() {
|
|
60
|
+
try {
|
|
61
|
+
const { startDate, endDate, provider } = parseArguments();
|
|
62
|
+
const config = loadConfig(startDate, endDate, provider);
|
|
63
|
+
const title = provider === 'claude' ? 'Claude API Usage Report' : 'OpenAI API Usage Report';
|
|
64
|
+
console.log(title);
|
|
65
|
+
console.log('=======================\n');
|
|
66
|
+
console.log(`Fetching costs from ${startDate} to ${endDate}...`);
|
|
67
|
+
const buckets = config.provider === 'openai'
|
|
68
|
+
? await fetchOpenAICosts(config)
|
|
69
|
+
: await fetchClaudeCosts(config);
|
|
70
|
+
console.log(`Received ${buckets.length} daily buckets\n`);
|
|
71
|
+
const projectId = config.provider === 'openai' ? config.projectId : 'default';
|
|
72
|
+
const orgId = config.provider === 'openai' ? config.orgId : 'default';
|
|
73
|
+
const aggregated = aggregateCosts(buckets, startDate, endDate, projectId);
|
|
74
|
+
const { mdPath, csvPath, jsonPath } = writeReports(aggregated, orgId, provider);
|
|
75
|
+
console.log('');
|
|
76
|
+
displayTerminalSummary(aggregated, mdPath, csvPath, jsonPath, provider);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof Error) {
|
|
80
|
+
console.error('Error:', error.message);
|
|
81
|
+
if (error.message.includes('OPENAI_ADMIN_KEY')) {
|
|
82
|
+
console.error('\nHint: Make sure OPENAI_ADMIN_KEY is set in your environment.');
|
|
83
|
+
}
|
|
84
|
+
else if (error.message.includes('OPENAI_ORG_ID')) {
|
|
85
|
+
console.error('\nHint: Make sure OPENAI_ORG_ID is set in your environment.');
|
|
86
|
+
}
|
|
87
|
+
else if (error.message.includes('OPENAI_PROJECT_ID')) {
|
|
88
|
+
console.error('\nHint: Make sure OPENAI_PROJECT_ID is set in your environment.');
|
|
89
|
+
}
|
|
90
|
+
else if (error.message.includes('ANTHROPIC_ADMIN_API_KEY')) {
|
|
91
|
+
console.error('\nHint: Make sure ANTHROPIC_ADMIN_API_KEY is set in your environment.');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!process.env.VITEST) {
|
|
98
|
+
main().catch((error) => {
|
|
99
|
+
console.error('Unexpected error:', error);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Exports all public API functions and types for programmatic use.
|
|
5
|
+
* This is the main entry point when using this package as a library.
|
|
6
|
+
*/
|
|
7
|
+
export type { AggregatedCosts, ClaudeCostBucket, ClaudeCostReport, ClaudeCostResult, ClaudeReportConfig, CostBucket, CostsResponse, DailyCost, OpenAIReportConfig, Provider, ReportConfig, } from './types.js';
|
|
8
|
+
export { parseDate, validateDateRange, loadConfig, aggregateCosts, generateMarkdownReport, generateCSVReport, generateJSONReport, writeReports, fetchOpenAICosts, fetchClaudeCosts, } from './usage-report.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,QAAQ,EACR,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Exports all public API functions and types for programmatic use.
|
|
5
|
+
* This is the main entry point when using this package as a library.
|
|
6
|
+
*/
|
|
7
|
+
// Re-export public utility functions
|
|
8
|
+
export { parseDate, validateDateRange, loadConfig, aggregateCosts, generateMarkdownReport, generateCSVReport, generateJSONReport, writeReports, fetchOpenAICosts, fetchClaudeCosts, } from './usage-report.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,qCAAqC;AACrC,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
// Test that the library entry point exists and exports all expected functions
|
|
3
|
+
describe('Library Entry Point (index.ts)', () => {
|
|
4
|
+
it('should export all public API functions', async () => {
|
|
5
|
+
// Dynamic import to test the library entry point
|
|
6
|
+
const lib = await import('./index.js');
|
|
7
|
+
// Core functions
|
|
8
|
+
expect(typeof lib.parseDate).toBe('function');
|
|
9
|
+
expect(typeof lib.validateDateRange).toBe('function');
|
|
10
|
+
expect(typeof lib.loadConfig).toBe('function');
|
|
11
|
+
expect(typeof lib.fetchOpenAICosts).toBe('function');
|
|
12
|
+
expect(typeof lib.fetchClaudeCosts).toBe('function');
|
|
13
|
+
expect(typeof lib.aggregateCosts).toBe('function');
|
|
14
|
+
expect(typeof lib.generateMarkdownReport).toBe('function');
|
|
15
|
+
expect(typeof lib.generateCSVReport).toBe('function');
|
|
16
|
+
expect(typeof lib.writeReports).toBe('function');
|
|
17
|
+
});
|
|
18
|
+
it('should export all types', async () => {
|
|
19
|
+
const lib = await import('./index.js');
|
|
20
|
+
// Types should be available (as TypeScript types, not runtime values)
|
|
21
|
+
// We can't directly test types at runtime, but we can verify the module exports
|
|
22
|
+
expect(lib).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
it('should NOT export CLI-specific functions', async () => {
|
|
25
|
+
const lib = await import('./index.js');
|
|
26
|
+
// CLI-specific functions should not be exported
|
|
27
|
+
expect('parseArguments' in lib).toBe(false);
|
|
28
|
+
expect('main' in lib).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('should allow importing without CLI dependencies', async () => {
|
|
31
|
+
// This test verifies the library can be imported without dotenv/config
|
|
32
|
+
// which is only needed for CLI
|
|
33
|
+
const lib = await import('./index.js');
|
|
34
|
+
expect(lib).toBeDefined();
|
|
35
|
+
expect(typeof lib.fetchOpenAICosts).toBe('function');
|
|
36
|
+
expect(typeof lib.fetchClaudeCosts).toBe('function');
|
|
37
|
+
});
|
|
38
|
+
it('should export fetchOpenAICosts (renamed from fetchCosts)', async () => {
|
|
39
|
+
const lib = await import('./index.js');
|
|
40
|
+
// Verify the renamed function exists
|
|
41
|
+
expect(typeof lib.fetchOpenAICosts).toBe('function');
|
|
42
|
+
// Verify old name doesn't exist
|
|
43
|
+
expect('fetchCosts' in lib).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAS9C,8EAA8E;AAC9E,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,iDAAiD;QACjD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,iBAAiB;QACjB,MAAM,CAAC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,MAAM,CAAC,OAAO,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,sEAAsE;QACtE,gFAAgF;QAChF,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,gDAAgD;QAChD,MAAM,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,uEAAuE;QACvE,+BAA+B;QAC/B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,qCAAqC;QACrC,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,gCAAgC;QAChC,MAAM,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Integration tests to verify both CLI and library usage patterns work
|
|
4
|
+
*/
|
|
5
|
+
describe('Integration: CLI and Library Usage', () => {
|
|
6
|
+
it('should allow importing CLI functions', async () => {
|
|
7
|
+
const cli = await import('./cli.js');
|
|
8
|
+
// Verify CLI-specific functions are available
|
|
9
|
+
expect(typeof cli.parseArguments).toBe('function');
|
|
10
|
+
});
|
|
11
|
+
it('should allow importing library functions', async () => {
|
|
12
|
+
const lib = await import('./index.js');
|
|
13
|
+
// Verify core library functions are available
|
|
14
|
+
expect(typeof lib.fetchOpenAICosts).toBe('function');
|
|
15
|
+
expect(typeof lib.fetchClaudeCosts).toBe('function');
|
|
16
|
+
expect(typeof lib.aggregateCosts).toBe('function');
|
|
17
|
+
expect(typeof lib.generateMarkdownReport).toBe('function');
|
|
18
|
+
expect(typeof lib.generateCSVReport).toBe('function');
|
|
19
|
+
expect(typeof lib.writeReports).toBe('function');
|
|
20
|
+
expect(typeof lib.parseDate).toBe('function');
|
|
21
|
+
expect(typeof lib.validateDateRange).toBe('function');
|
|
22
|
+
expect(typeof lib.loadConfig).toBe('function');
|
|
23
|
+
});
|
|
24
|
+
it('should allow importing types from library', async () => {
|
|
25
|
+
const lib = await import('./index.js');
|
|
26
|
+
// Types are available at compile time, but we can verify the module exports
|
|
27
|
+
expect(lib).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
it('should have CLI import from library (verify separation)', async () => {
|
|
30
|
+
// This test verifies that cli.ts imports from index.ts (the library)
|
|
31
|
+
// We can't directly test imports, but we can verify both modules work
|
|
32
|
+
const cli = await import('./cli.js');
|
|
33
|
+
const lib = await import('./index.js');
|
|
34
|
+
// Both should be importable
|
|
35
|
+
expect(cli).toBeDefined();
|
|
36
|
+
expect(lib).toBeDefined();
|
|
37
|
+
// CLI should have parseArguments (CLI-specific)
|
|
38
|
+
expect(typeof cli.parseArguments).toBe('function');
|
|
39
|
+
// Library should have core functions but NOT CLI functions
|
|
40
|
+
expect(typeof lib.fetchOpenAICosts).toBe('function');
|
|
41
|
+
expect('parseArguments' in lib).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../src/integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C;;GAEG;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QAErC,8CAA8C;QAC9C,MAAM,CAAC,OAAO,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,8CAA8C;QAC9C,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,MAAM,CAAC,OAAO,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,4EAA4E;QAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,qEAAqE;QACrE,sEAAsE;QACtE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAEvC,4BAA4B;QAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAE1B,gDAAgD;QAChD,MAAM,CAAC,OAAO,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEnD,2DAA2D;QAC3D,MAAM,CAAC,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Organization Costs API Types
|
|
3
|
+
* https://platform.openai.com/docs/api-reference/usage
|
|
4
|
+
*
|
|
5
|
+
* Claude (Anthropic) Cost API Types
|
|
6
|
+
* https://platform.claude.com/docs/en/build-with-claude/usage-cost-api
|
|
7
|
+
*/
|
|
8
|
+
export type Provider = 'openai' | 'claude';
|
|
9
|
+
export interface CostsResponse {
|
|
10
|
+
object: 'page';
|
|
11
|
+
data: CostBucket[];
|
|
12
|
+
has_more: boolean;
|
|
13
|
+
next_page: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface CostBucket {
|
|
16
|
+
object: 'bucket';
|
|
17
|
+
start_time: number;
|
|
18
|
+
end_time: number;
|
|
19
|
+
results: CostResult[];
|
|
20
|
+
}
|
|
21
|
+
export interface CostResult {
|
|
22
|
+
object: 'organization.costs.result';
|
|
23
|
+
amount: {
|
|
24
|
+
value: number | string;
|
|
25
|
+
currency: string;
|
|
26
|
+
};
|
|
27
|
+
line_item: string | null;
|
|
28
|
+
project_id: string | null;
|
|
29
|
+
}
|
|
30
|
+
/** Anthropic cost_report API response (raw). */
|
|
31
|
+
export interface ClaudeCostReport {
|
|
32
|
+
data: ClaudeCostBucket[];
|
|
33
|
+
has_more: boolean;
|
|
34
|
+
next_page: string | null;
|
|
35
|
+
}
|
|
36
|
+
export interface ClaudeCostBucket {
|
|
37
|
+
starting_at: string;
|
|
38
|
+
ending_at: string;
|
|
39
|
+
results: ClaudeCostResult[];
|
|
40
|
+
}
|
|
41
|
+
export interface ClaudeCostResult {
|
|
42
|
+
amount: string;
|
|
43
|
+
currency: string;
|
|
44
|
+
description: string | null;
|
|
45
|
+
model: string | null;
|
|
46
|
+
cost_type: string | null;
|
|
47
|
+
context_window: string | null;
|
|
48
|
+
token_type: string | null;
|
|
49
|
+
service_tier: string | null;
|
|
50
|
+
workspace_id: string | null;
|
|
51
|
+
}
|
|
52
|
+
export interface AggregatedCosts {
|
|
53
|
+
totalCost: number;
|
|
54
|
+
startDate: string;
|
|
55
|
+
endDate: string;
|
|
56
|
+
projectId: string;
|
|
57
|
+
dailyCosts: DailyCost[];
|
|
58
|
+
costsByLineItem: Map<string, number>;
|
|
59
|
+
billingDays: number;
|
|
60
|
+
averageDailyCost: number;
|
|
61
|
+
}
|
|
62
|
+
export interface DailyCost {
|
|
63
|
+
date: string;
|
|
64
|
+
lineItem: string;
|
|
65
|
+
cost: number;
|
|
66
|
+
}
|
|
67
|
+
export interface OpenAIReportConfig {
|
|
68
|
+
provider: 'openai';
|
|
69
|
+
startDate: string;
|
|
70
|
+
endDate: string;
|
|
71
|
+
apiKey: string;
|
|
72
|
+
orgId: string;
|
|
73
|
+
projectId: string;
|
|
74
|
+
}
|
|
75
|
+
export interface ClaudeReportConfig {
|
|
76
|
+
provider: 'claude';
|
|
77
|
+
startDate: string;
|
|
78
|
+
endDate: string;
|
|
79
|
+
apiKey: string;
|
|
80
|
+
}
|
|
81
|
+
export type ReportConfig = OpenAIReportConfig | ClaudeReportConfig;
|
|
82
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,kBAAkB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Organization Costs API Types
|
|
3
|
+
* https://platform.openai.com/docs/api-reference/usage
|
|
4
|
+
*
|
|
5
|
+
* Claude (Anthropic) Cost API Types
|
|
6
|
+
* https://platform.claude.com/docs/en/build-with-claude/usage-cost-api
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AggregatedCosts, CostBucket, type ClaudeReportConfig, type OpenAIReportConfig, type ReportConfig, type Provider } from './types.js';
|
|
2
|
+
export declare function parseDate(dateStr: string): Date;
|
|
3
|
+
export declare function validateDateRange(start: Date, end: Date): void;
|
|
4
|
+
export declare function toUnixTimestamp(date: Date): number;
|
|
5
|
+
export declare function loadConfig(startDate: string, endDate: string, provider: Provider): ReportConfig;
|
|
6
|
+
export declare function fetchOpenAICosts(config: OpenAIReportConfig): Promise<CostBucket[]>;
|
|
7
|
+
export declare function fetchClaudeCosts(config: ClaudeReportConfig): Promise<CostBucket[]>;
|
|
8
|
+
export declare function aggregateCosts(buckets: CostBucket[], startDate: string, endDate: string, projectId: string): AggregatedCosts;
|
|
9
|
+
export declare function generateMarkdownReport(aggregated: AggregatedCosts, orgId: string, provider: 'openai' | 'claude'): string;
|
|
10
|
+
export declare function generateCSVReport(aggregated: AggregatedCosts): string;
|
|
11
|
+
export declare function generateJSONReport(aggregated: AggregatedCosts, orgId: string, provider: 'openai' | 'claude'): string;
|
|
12
|
+
export declare function writeReports(aggregated: AggregatedCosts, orgId: string, provider: Provider, baseDir?: string): {
|
|
13
|
+
mdPath: string;
|
|
14
|
+
csvPath: string;
|
|
15
|
+
jsonPath: string;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=usage-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-report.d.ts","sourceRoot":"","sources":["../src/usage-report.ts"],"names":[],"mappings":"AASA,OAAO,EACL,eAAe,EAGf,UAAU,EAGV,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAOpB,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAkB/C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,CAI9D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAElD;AAED,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,GACjB,YAAY,CAyBd;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAsCxF;AA2BD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAoCxF;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,UAAU,EAAE,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,eAAe,CA2CjB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAC5B,MAAM,CAgFR;AAaD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAoBrE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAqDpH;AAmBD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,eAAe,EAC3B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiBvD"}
|