@revenium/claude-code-metering 0.1.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/CHANGELOG.md +50 -0
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/cli/commands/backfill.d.ts +11 -0
- package/dist/cli/commands/backfill.d.ts.map +1 -0
- package/dist/cli/commands/backfill.js +390 -0
- package/dist/cli/commands/backfill.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +13 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +177 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +5 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +95 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/test.d.ts +9 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/test.js +67 -0
- package/dist/cli/commands/test.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +65 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/api/client.d.ts +28 -0
- package/dist/core/api/client.d.ts.map +1 -0
- package/dist/core/api/client.js +127 -0
- package/dist/core/api/client.js.map +1 -0
- package/dist/core/config/loader.d.ts +35 -0
- package/dist/core/config/loader.d.ts.map +1 -0
- package/dist/core/config/loader.js +162 -0
- package/dist/core/config/loader.js.map +1 -0
- package/dist/core/config/validator.d.ts +19 -0
- package/dist/core/config/validator.d.ts.map +1 -0
- package/dist/core/config/validator.js +101 -0
- package/dist/core/config/validator.js.map +1 -0
- package/dist/core/config/writer.d.ts +11 -0
- package/dist/core/config/writer.d.ts.map +1 -0
- package/dist/core/config/writer.js +145 -0
- package/dist/core/config/writer.js.map +1 -0
- package/dist/core/shell/detector.d.ts +14 -0
- package/dist/core/shell/detector.d.ts.map +1 -0
- package/dist/core/shell/detector.js +69 -0
- package/dist/core/shell/detector.js.map +1 -0
- package/dist/core/shell/profile-updater.d.ts +11 -0
- package/dist/core/shell/profile-updater.d.ts.map +1 -0
- package/dist/core/shell/profile-updater.js +101 -0
- package/dist/core/shell/profile-updater.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +96 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/constants.d.ts +68 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +73 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/masking.d.ts +14 -0
- package/dist/utils/masking.d.ts.map +1 -0
- package/dist/utils/masking.js +33 -0
- package/dist/utils/masking.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.statusCommand = statusCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const loader_js_1 = require("../../core/config/loader.js");
|
|
10
|
+
const client_js_1 = require("../../core/api/client.js");
|
|
11
|
+
const masking_js_1 = require("../../utils/masking.js");
|
|
12
|
+
const detector_js_1 = require("../../core/shell/detector.js");
|
|
13
|
+
/**
|
|
14
|
+
* Displays the current configuration status.
|
|
15
|
+
*/
|
|
16
|
+
async function statusCommand() {
|
|
17
|
+
console.log(chalk_1.default.bold('\nRevenium Claude Code Metering Status\n'));
|
|
18
|
+
// Check if config file exists
|
|
19
|
+
const configPath = (0, loader_js_1.getConfigPath)();
|
|
20
|
+
if (!(0, loader_js_1.configExists)()) {
|
|
21
|
+
console.log(chalk_1.default.red('Configuration not found'));
|
|
22
|
+
console.log(chalk_1.default.dim(`Expected at: ${configPath}`));
|
|
23
|
+
console.log(chalk_1.default.yellow('\nRun `revenium-metering setup` to configure Claude Code metering.'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
console.log(chalk_1.default.green('Configuration file found'));
|
|
27
|
+
console.log(chalk_1.default.dim(` ${configPath}`));
|
|
28
|
+
// Load and display configuration
|
|
29
|
+
const config = await (0, loader_js_1.loadConfig)();
|
|
30
|
+
if (!config) {
|
|
31
|
+
console.log(chalk_1.default.red('\nCould not parse configuration file'));
|
|
32
|
+
console.log(chalk_1.default.yellow('Run `revenium-metering setup` to reconfigure.'));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
console.log('\n' + chalk_1.default.bold('Configuration:'));
|
|
36
|
+
console.log(` API Key: ${(0, masking_js_1.maskApiKey)(config.apiKey)}`);
|
|
37
|
+
console.log(` Endpoint: ${config.endpoint}`);
|
|
38
|
+
if (config.email) {
|
|
39
|
+
console.log(` Email: ${(0, masking_js_1.maskEmail)(config.email)}`);
|
|
40
|
+
}
|
|
41
|
+
if (config.subscriptionTier) {
|
|
42
|
+
console.log(` Tier: ${config.subscriptionTier}`);
|
|
43
|
+
}
|
|
44
|
+
if (config.organizationId) {
|
|
45
|
+
console.log(` Org ID: ${config.organizationId}`);
|
|
46
|
+
}
|
|
47
|
+
if (config.productId) {
|
|
48
|
+
console.log(` Product ID: ${config.productId}`);
|
|
49
|
+
}
|
|
50
|
+
// Check for migration issues
|
|
51
|
+
const migrationStatus = await (0, loader_js_1.checkMigrationStatus)();
|
|
52
|
+
if (migrationStatus.needsMigration) {
|
|
53
|
+
console.log('\n' + chalk_1.default.bold.yellow('⚠️ Migration Required:'));
|
|
54
|
+
for (const issue of migrationStatus.issues) {
|
|
55
|
+
console.log(chalk_1.default.yellow(` • ${issue}`));
|
|
56
|
+
}
|
|
57
|
+
console.log(chalk_1.default.dim(' Run `revenium-metering setup` to update your configuration.'));
|
|
58
|
+
}
|
|
59
|
+
// Check if environment is loaded
|
|
60
|
+
console.log('\n' + chalk_1.default.bold('Environment:'));
|
|
61
|
+
if ((0, loader_js_1.isEnvLoaded)()) {
|
|
62
|
+
console.log(chalk_1.default.green(' Environment variables are loaded in current shell'));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(chalk_1.default.yellow(' Environment variables not loaded in current shell'));
|
|
66
|
+
console.log(chalk_1.default.dim(' Run: source ~/.claude/revenium.env'));
|
|
67
|
+
}
|
|
68
|
+
// Shell profile status
|
|
69
|
+
const shellType = (0, detector_js_1.detectShell)();
|
|
70
|
+
const profilePath = (0, detector_js_1.getProfilePath)(shellType);
|
|
71
|
+
console.log(` Shell: ${shellType}`);
|
|
72
|
+
if (profilePath) {
|
|
73
|
+
console.log(` Profile: ${profilePath}`);
|
|
74
|
+
}
|
|
75
|
+
// Test endpoint connectivity
|
|
76
|
+
console.log('\n' + chalk_1.default.bold('Endpoint Health:'));
|
|
77
|
+
const spinner = (0, ora_1.default)(' Testing connectivity...').start();
|
|
78
|
+
try {
|
|
79
|
+
const healthResult = await (0, client_js_1.checkEndpointHealth)(config.endpoint, config.apiKey, {
|
|
80
|
+
organizationId: config.organizationId,
|
|
81
|
+
productId: config.productId,
|
|
82
|
+
});
|
|
83
|
+
if (healthResult.healthy) {
|
|
84
|
+
spinner.succeed(` Endpoint healthy (${healthResult.latencyMs}ms)`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
spinner.fail(` Endpoint unhealthy: ${healthResult.message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
spinner.fail(` Connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
92
|
+
}
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/test.ts"],"names":[],"mappings":"AASA,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyE1E"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.testCommand = testCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const loader_js_1 = require("../../core/config/loader.js");
|
|
10
|
+
const client_js_1 = require("../../core/api/client.js");
|
|
11
|
+
/**
|
|
12
|
+
* Sends a test metric to verify the integration.
|
|
13
|
+
*/
|
|
14
|
+
async function testCommand(options = {}) {
|
|
15
|
+
console.log(chalk_1.default.bold('\nRevenium Claude Code Metering Test\n'));
|
|
16
|
+
// Check if configured
|
|
17
|
+
if (!(0, loader_js_1.configExists)()) {
|
|
18
|
+
console.log(chalk_1.default.red('Configuration not found'));
|
|
19
|
+
console.log(chalk_1.default.yellow('Run `revenium-metering setup` first to configure the integration.'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
// Load configuration
|
|
23
|
+
const config = await (0, loader_js_1.loadConfig)();
|
|
24
|
+
if (!config) {
|
|
25
|
+
console.log(chalk_1.default.red('Could not load configuration'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
// Generate test payload with optional organization/product IDs
|
|
29
|
+
const sessionId = (0, client_js_1.generateTestSessionId)();
|
|
30
|
+
const payload = (0, client_js_1.createTestPayload)(sessionId, {
|
|
31
|
+
organizationId: config.organizationId,
|
|
32
|
+
productId: config.productId,
|
|
33
|
+
});
|
|
34
|
+
if (options.verbose) {
|
|
35
|
+
console.log(chalk_1.default.dim('Test payload:'));
|
|
36
|
+
console.log(chalk_1.default.dim(JSON.stringify(payload, null, 2)));
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
// Send test metric
|
|
40
|
+
const spinner = (0, ora_1.default)('Sending test metric...').start();
|
|
41
|
+
try {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const response = await (0, client_js_1.sendOtlpMetrics)(config.endpoint, config.apiKey, payload);
|
|
44
|
+
const latencyMs = Date.now() - startTime;
|
|
45
|
+
spinner.succeed(`Test metric sent successfully (${latencyMs}ms)`);
|
|
46
|
+
console.log('\n' + chalk_1.default.bold('Response:'));
|
|
47
|
+
console.log(` ID: ${response.id}`);
|
|
48
|
+
console.log(` Resource Type: ${response.resourceType}`);
|
|
49
|
+
console.log(` Processed: ${response.processedMetrics} metric(s)`);
|
|
50
|
+
console.log(` Created: ${response.created}`);
|
|
51
|
+
console.log('\n' + chalk_1.default.green.bold('Integration is working correctly!'));
|
|
52
|
+
console.log(chalk_1.default.dim('\nNote: This test metric uses session ID: ' + sessionId));
|
|
53
|
+
console.log(chalk_1.default.dim('You can verify it in the Revenium dashboard at https://app.revenium.ai'));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
spinner.fail('Failed to send test metric');
|
|
57
|
+
console.error(chalk_1.default.red(`\nError: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
58
|
+
console.log('\n' + chalk_1.default.yellow('Troubleshooting:'));
|
|
59
|
+
console.log(' 1. Verify your API key is correct');
|
|
60
|
+
console.log(' 2. Check the endpoint URL');
|
|
61
|
+
console.log(' 3. Ensure you have network connectivity');
|
|
62
|
+
console.log(' 4. Run `revenium-metering status` for more details');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
console.log('');
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/cli/commands/test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const setup_js_1 = require("./commands/setup.js");
|
|
6
|
+
const status_js_1 = require("./commands/status.js");
|
|
7
|
+
const test_js_1 = require("./commands/test.js");
|
|
8
|
+
const backfill_js_1 = require("./commands/backfill.js");
|
|
9
|
+
const program = new commander_1.Command();
|
|
10
|
+
program
|
|
11
|
+
.name('revenium-metering')
|
|
12
|
+
.description('Configure Claude Code telemetry export to Revenium')
|
|
13
|
+
.version('0.1.0');
|
|
14
|
+
program
|
|
15
|
+
.command('setup')
|
|
16
|
+
.description('Interactive setup wizard to configure Claude Code metering')
|
|
17
|
+
.option('-k, --api-key <key>', 'Revenium API key (hak_...)')
|
|
18
|
+
.option('-e, --email <email>', 'Email for usage attribution')
|
|
19
|
+
.option('-t, --tier <tier>', 'Subscription tier (pro, max_5x, max_20x, team_premium, enterprise, api)')
|
|
20
|
+
.option('--endpoint <url>', 'Revenium API endpoint URL')
|
|
21
|
+
.option('--skip-shell-update', 'Skip automatic shell profile update')
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
await (0, setup_js_1.setupCommand)({
|
|
24
|
+
apiKey: options.apiKey,
|
|
25
|
+
email: options.email,
|
|
26
|
+
tier: options.tier,
|
|
27
|
+
endpoint: options.endpoint,
|
|
28
|
+
skipShellUpdate: options.skipShellUpdate,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
program
|
|
32
|
+
.command('status')
|
|
33
|
+
.description('Check current configuration and endpoint connectivity')
|
|
34
|
+
.action(async () => {
|
|
35
|
+
await (0, status_js_1.statusCommand)();
|
|
36
|
+
});
|
|
37
|
+
program
|
|
38
|
+
.command('test')
|
|
39
|
+
.description('Send a test metric to verify the integration')
|
|
40
|
+
.option('-v, --verbose', 'Show detailed payload information')
|
|
41
|
+
.action(async (options) => {
|
|
42
|
+
await (0, test_js_1.testCommand)({ verbose: options.verbose });
|
|
43
|
+
});
|
|
44
|
+
program
|
|
45
|
+
.command('backfill')
|
|
46
|
+
.description('Import historical Claude Code usage data from local JSONL files')
|
|
47
|
+
.option('--since <date>', 'Only backfill after this date (ISO format or relative like "7d", "1m")')
|
|
48
|
+
.option('--dry-run', 'Show what would be sent without sending')
|
|
49
|
+
.option('--batch-size <n>', 'Messages per API batch (default: 100)', '100')
|
|
50
|
+
.option('-v, --verbose', 'Show detailed progress')
|
|
51
|
+
.action(async (options) => {
|
|
52
|
+
const batchSize = parseInt(options.batchSize, 10);
|
|
53
|
+
if (!Number.isFinite(batchSize) || batchSize < 1) {
|
|
54
|
+
console.error('Error: --batch-size must be a positive integer');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
await (0, backfill_js_1.backfillCommand)({
|
|
58
|
+
since: options.since,
|
|
59
|
+
dryRun: options.dryRun,
|
|
60
|
+
batchSize,
|
|
61
|
+
verbose: options.verbose,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
program.parse();
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,kDAAmD;AACnD,oDAAqD;AACrD,gDAAiD;AACjD,wDAAyD;AAEzD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,mBAAmB,CAAC;KACzB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,MAAM,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KAC3D,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,CAAC;KAC5D,MAAM,CAAC,mBAAmB,EAAE,yEAAyE,CAAC;KACtG,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,CAAC;KACvD,MAAM,CAAC,qBAAqB,EAAE,qCAAqC,CAAC;KACpE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,IAAA,uBAAY,EAAC;QACjB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,OAAO,CAAC,eAAe;KACzC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,IAAA,yBAAa,GAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,8CAA8C,CAAC;KAC3D,MAAM,CAAC,eAAe,EAAE,mCAAmC,CAAC;KAC5D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,IAAA,qBAAW,EAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,MAAM,CAAC,gBAAgB,EAAE,wEAAwE,CAAC;KAClG,MAAM,CAAC,WAAW,EAAE,yCAAyC,CAAC;KAC9D,MAAM,CAAC,kBAAkB,EAAE,uCAAuC,EAAE,KAAK,CAAC;KAC1E,MAAM,CAAC,eAAe,EAAE,wBAAwB,CAAC;KACjD,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,IAAA,6BAAe,EAAC;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS;QACT,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { OTLPMetricsPayload, OTLPResponse, HealthCheckResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sends an OTLP metrics payload to the Revenium endpoint.
|
|
4
|
+
* Posts to /meter/v2/otel/v1/metrics with OTEL Metrics format.
|
|
5
|
+
*/
|
|
6
|
+
export declare function sendOtlpMetrics(baseEndpoint: string, apiKey: string, payload: OTLPMetricsPayload): Promise<OTLPResponse>;
|
|
7
|
+
/**
|
|
8
|
+
* Options for creating a test payload.
|
|
9
|
+
*/
|
|
10
|
+
export interface TestPayloadOptions {
|
|
11
|
+
/** Optional organization ID to attribute costs to */
|
|
12
|
+
organizationId?: string;
|
|
13
|
+
/** Optional product ID to attribute costs to */
|
|
14
|
+
productId?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a minimal test OTEL metrics payload.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createTestPayload(sessionId: string, options?: TestPayloadOptions): OTLPMetricsPayload;
|
|
20
|
+
/**
|
|
21
|
+
* Generates a unique session ID for test payloads.
|
|
22
|
+
*/
|
|
23
|
+
export declare function generateTestSessionId(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Performs a health check by sending a minimal test payload to the endpoint.
|
|
26
|
+
*/
|
|
27
|
+
export declare function checkEndpointHealth(baseEndpoint: string, apiKey: string, options?: TestPayloadOptions): Promise<HealthCheckResult>;
|
|
28
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGhG;;;GAGG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,CA4DrG;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAI9C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CA+B5B"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendOtlpMetrics = sendOtlpMetrics;
|
|
4
|
+
exports.createTestPayload = createTestPayload;
|
|
5
|
+
exports.generateTestSessionId = generateTestSessionId;
|
|
6
|
+
exports.checkEndpointHealth = checkEndpointHealth;
|
|
7
|
+
const loader_js_1 = require("../config/loader.js");
|
|
8
|
+
/**
|
|
9
|
+
* Sends an OTLP metrics payload to the Revenium endpoint.
|
|
10
|
+
* Posts to /meter/v2/otel/v1/metrics with OTEL Metrics format.
|
|
11
|
+
*/
|
|
12
|
+
async function sendOtlpMetrics(baseEndpoint, apiKey, payload) {
|
|
13
|
+
const fullEndpoint = (0, loader_js_1.getFullOtlpEndpoint)(baseEndpoint);
|
|
14
|
+
const url = `${fullEndpoint}/v1/metrics`;
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
'x-api-key': apiKey,
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(payload),
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const errorText = await response.text();
|
|
25
|
+
throw new Error(`OTLP request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
26
|
+
}
|
|
27
|
+
return response.json();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a minimal test OTEL metrics payload.
|
|
31
|
+
*/
|
|
32
|
+
function createTestPayload(sessionId, options) {
|
|
33
|
+
const now = Date.now() * 1_000_000; // Convert to nanoseconds
|
|
34
|
+
// Common attributes for all metrics
|
|
35
|
+
const commonAttributes = [
|
|
36
|
+
{ key: 'ai.transaction_id', value: { stringValue: sessionId } },
|
|
37
|
+
{ key: 'ai.model', value: { stringValue: 'cli-connectivity-test' } },
|
|
38
|
+
{ key: 'ai.provider', value: { stringValue: 'anthropic' } },
|
|
39
|
+
];
|
|
40
|
+
// Add optional organization ID
|
|
41
|
+
if (options?.organizationId) {
|
|
42
|
+
commonAttributes.push({ key: 'organization.id', value: { stringValue: options.organizationId } });
|
|
43
|
+
}
|
|
44
|
+
// Add optional product ID
|
|
45
|
+
if (options?.productId) {
|
|
46
|
+
commonAttributes.push({ key: 'product.id', value: { stringValue: options.productId } });
|
|
47
|
+
}
|
|
48
|
+
// Build resource attributes
|
|
49
|
+
const resourceAttributes = [
|
|
50
|
+
{ key: 'service.name', value: { stringValue: 'claude-code' } },
|
|
51
|
+
];
|
|
52
|
+
return {
|
|
53
|
+
resourceMetrics: [
|
|
54
|
+
{
|
|
55
|
+
resource: {
|
|
56
|
+
attributes: resourceAttributes,
|
|
57
|
+
},
|
|
58
|
+
scopeMetrics: [
|
|
59
|
+
{
|
|
60
|
+
metrics: [
|
|
61
|
+
{
|
|
62
|
+
name: 'ai.tokens.input',
|
|
63
|
+
sum: {
|
|
64
|
+
dataPoints: [{
|
|
65
|
+
attributes: commonAttributes,
|
|
66
|
+
timeUnixNano: now.toString(),
|
|
67
|
+
asInt: 0,
|
|
68
|
+
}],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'ai.tokens.output',
|
|
73
|
+
sum: {
|
|
74
|
+
dataPoints: [{
|
|
75
|
+
attributes: commonAttributes,
|
|
76
|
+
timeUnixNano: now.toString(),
|
|
77
|
+
asInt: 0,
|
|
78
|
+
}],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generates a unique session ID for test payloads.
|
|
90
|
+
*/
|
|
91
|
+
function generateTestSessionId() {
|
|
92
|
+
const timestamp = Date.now().toString(36);
|
|
93
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
94
|
+
return `test-${timestamp}-${random}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Performs a health check by sending a minimal test payload to the endpoint.
|
|
98
|
+
*/
|
|
99
|
+
async function checkEndpointHealth(baseEndpoint, apiKey, options) {
|
|
100
|
+
const startTime = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
const sessionId = generateTestSessionId();
|
|
103
|
+
const payload = createTestPayload(sessionId, options);
|
|
104
|
+
const response = await sendOtlpMetrics(baseEndpoint, apiKey, payload);
|
|
105
|
+
const latencyMs = Date.now() - startTime;
|
|
106
|
+
return {
|
|
107
|
+
healthy: true,
|
|
108
|
+
statusCode: 200,
|
|
109
|
+
message: `Endpoint healthy. Processed ${response.processedMetrics} metric(s).`,
|
|
110
|
+
latencyMs,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const latencyMs = Date.now() - startTime;
|
|
115
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
116
|
+
// Try to extract status code from error message
|
|
117
|
+
const statusMatch = message.match(/(\d{3})/);
|
|
118
|
+
const statusCode = statusMatch ? parseInt(statusMatch[1], 10) : undefined;
|
|
119
|
+
return {
|
|
120
|
+
healthy: false,
|
|
121
|
+
statusCode,
|
|
122
|
+
message,
|
|
123
|
+
latencyMs,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":";;AAOA,0CAuBC;AAeD,8CA4DC;AAKD,sDAIC;AAKD,kDAmCC;AAzJD,mDAA0D;AAE1D;;;GAGG;AACI,KAAK,UAAU,eAAe,CACnC,YAAoB,EACpB,MAAc,EACd,OAA2B;IAE3B,MAAM,YAAY,GAAG,IAAA,+BAAmB,EAAC,YAAY,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,GAAG,YAAY,aAAa,CAAC;IAEzC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,MAAM;SACpB;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,SAAS,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA2B,CAAC;AAClD,CAAC;AAYD;;GAEG;AACH,SAAgB,iBAAiB,CAAC,SAAiB,EAAE,OAA4B;IAC/E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,yBAAyB;IAE7D,oCAAoC;IACpC,MAAM,gBAAgB,GAA2D;QAC/E,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE;QAC/D,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,uBAAuB,EAAE,EAAE;QACpE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE;KAC5D,CAAC;IAEF,+BAA+B;IAC/B,IAAI,OAAO,EAAE,cAAc,EAAE,CAAC;QAC5B,gBAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACpG,CAAC;IAED,0BAA0B;IAC1B,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;QACvB,gBAAgB,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,4BAA4B;IAC5B,MAAM,kBAAkB,GAA2D;QACjF,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE;KAC/D,CAAC;IAEF,OAAO;QACL,eAAe,EAAE;YACf;gBACE,QAAQ,EAAE;oBACR,UAAU,EAAE,kBAAkB;iBAC/B;gBACD,YAAY,EAAE;oBACZ;wBACE,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,iBAAiB;gCACvB,GAAG,EAAE;oCACH,UAAU,EAAE,CAAC;4CACX,UAAU,EAAE,gBAAgB;4CAC5B,YAAY,EAAE,GAAG,CAAC,QAAQ,EAAE;4CAC5B,KAAK,EAAE,CAAC;yCACT,CAAC;iCACH;6BACF;4BACD;gCACE,IAAI,EAAE,kBAAkB;gCACxB,GAAG,EAAE;oCACH,UAAU,EAAE,CAAC;4CACX,UAAU,EAAE,gBAAgB;4CAC5B,YAAY,EAAE,GAAG,CAAC,QAAQ,EAAE;4CAC5B,KAAK,EAAE,CAAC;yCACT,CAAC;iCACH;6BACF;yBACF;qBACF;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,qBAAqB;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,QAAQ,SAAS,IAAI,MAAM,EAAE,CAAC;AACvC,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,mBAAmB,CACvC,YAAoB,EACpB,MAAc,EACd,OAA4B;IAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,qBAAqB,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAEtE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEzC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,+BAA+B,QAAQ,CAAC,gBAAgB,aAAa;YAC9E,SAAS;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACzC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QAEzE,gDAAgD;QAChD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1E,OAAO;YACL,OAAO,EAAE,KAAK;YACd,UAAU;YACV,OAAO;YACP,SAAS;SACV,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReveniumConfig } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Gets the path to the Revenium configuration file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getConfigPath(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Checks if the configuration file exists.
|
|
8
|
+
*/
|
|
9
|
+
export declare function configExists(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Loads the Revenium configuration from the .env file.
|
|
12
|
+
* Returns null if the file doesn't exist.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadConfig(): Promise<ReveniumConfig | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Checks if the environment variables are currently loaded in the shell.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isEnvLoaded(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Migration status for config file updates.
|
|
21
|
+
*/
|
|
22
|
+
export interface MigrationStatus {
|
|
23
|
+
needsMigration: boolean;
|
|
24
|
+
issues: string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Checks if the config file needs migration from old format.
|
|
28
|
+
* Detects: OTEL_LOGS_EXPORTER (should be OTEL_METRICS_EXPORTER)
|
|
29
|
+
*/
|
|
30
|
+
export declare function checkMigrationStatus(): Promise<MigrationStatus>;
|
|
31
|
+
/**
|
|
32
|
+
* Gets the full OTLP endpoint URL from a base URL.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getFullOtlpEndpoint(baseUrl: string): string;
|
|
35
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/config/loader.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAuED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmCjE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAKrC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,eAAe,CAAC,CA4BrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getConfigPath = getConfigPath;
|
|
4
|
+
exports.configExists = configExists;
|
|
5
|
+
exports.loadConfig = loadConfig;
|
|
6
|
+
exports.isEnvLoaded = isEnvLoaded;
|
|
7
|
+
exports.checkMigrationStatus = checkMigrationStatus;
|
|
8
|
+
exports.getFullOtlpEndpoint = getFullOtlpEndpoint;
|
|
9
|
+
const node_os_1 = require("node:os");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const constants_js_1 = require("../../utils/constants.js");
|
|
14
|
+
/**
|
|
15
|
+
* Gets the path to the Revenium configuration file.
|
|
16
|
+
*/
|
|
17
|
+
function getConfigPath() {
|
|
18
|
+
return (0, node_path_1.join)((0, node_os_1.homedir)(), constants_js_1.CLAUDE_CONFIG_DIR, constants_js_1.REVENIUM_ENV_FILE);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Checks if the configuration file exists.
|
|
22
|
+
*/
|
|
23
|
+
function configExists() {
|
|
24
|
+
return (0, node_fs_1.existsSync)(getConfigPath());
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parses an .env file content into key-value pairs.
|
|
28
|
+
*/
|
|
29
|
+
function parseEnvContent(content) {
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const line of content.split('\n')) {
|
|
32
|
+
let trimmed = line.trim();
|
|
33
|
+
// Skip empty lines and comments
|
|
34
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Handle 'export' prefix
|
|
38
|
+
if (trimmed.startsWith('export ')) {
|
|
39
|
+
trimmed = trimmed.substring(7).trim();
|
|
40
|
+
}
|
|
41
|
+
const equalsIndex = trimmed.indexOf('=');
|
|
42
|
+
if (equalsIndex === -1) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const key = trimmed.substring(0, equalsIndex).trim();
|
|
46
|
+
let value = trimmed.substring(equalsIndex + 1).trim();
|
|
47
|
+
// Remove surrounding quotes if present
|
|
48
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
49
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
50
|
+
value = value.substring(1, value.length - 1);
|
|
51
|
+
}
|
|
52
|
+
result[key] = value;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extracts the API key from the OTEL_EXPORTER_OTLP_HEADERS value.
|
|
58
|
+
* Format: "x-api-key=hak_xxx"
|
|
59
|
+
*/
|
|
60
|
+
function extractApiKeyFromHeaders(headers) {
|
|
61
|
+
const match = headers.match(/x-api-key=\s*(hak_[^\s"]+)/);
|
|
62
|
+
return match?.[1];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extracts the base endpoint from the full OTLP endpoint URL.
|
|
66
|
+
* Example: "https://api.revenium.ai/meter/v2/otlp" -> "https://api.revenium.ai"
|
|
67
|
+
*/
|
|
68
|
+
function extractBaseEndpoint(fullEndpoint) {
|
|
69
|
+
try {
|
|
70
|
+
const url = new URL(fullEndpoint);
|
|
71
|
+
// Remove the OTLP path suffix to get the base URL
|
|
72
|
+
// Handle both old path (/meter/v2/ai/otlp) and new path (/meter/v2/otlp)
|
|
73
|
+
const path = url.pathname;
|
|
74
|
+
if (path.includes('/meter/v2/otlp') || path.includes('/meter/v2/ai/otlp')) {
|
|
75
|
+
url.pathname = '';
|
|
76
|
+
}
|
|
77
|
+
return url.origin;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return fullEndpoint;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Loads the Revenium configuration from the .env file.
|
|
85
|
+
* Returns null if the file doesn't exist.
|
|
86
|
+
*/
|
|
87
|
+
async function loadConfig() {
|
|
88
|
+
const configPath = getConfigPath();
|
|
89
|
+
if (!(0, node_fs_1.existsSync)(configPath)) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const content = await (0, promises_1.readFile)(configPath, 'utf-8');
|
|
94
|
+
const env = parseEnvContent(content);
|
|
95
|
+
const fullEndpoint = env[constants_js_1.ENV_VARS.OTLP_ENDPOINT] || '';
|
|
96
|
+
const headers = env[constants_js_1.ENV_VARS.OTLP_HEADERS] || '';
|
|
97
|
+
const apiKey = extractApiKeyFromHeaders(headers);
|
|
98
|
+
if (!apiKey) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
// Parse cost multiplier override if present
|
|
102
|
+
const costMultiplierStr = env[constants_js_1.ENV_VARS.COST_MULTIPLIER];
|
|
103
|
+
const costMultiplierOverride = costMultiplierStr ? parseFloat(costMultiplierStr) : undefined;
|
|
104
|
+
return {
|
|
105
|
+
apiKey,
|
|
106
|
+
endpoint: extractBaseEndpoint(fullEndpoint),
|
|
107
|
+
email: env[constants_js_1.ENV_VARS.SUBSCRIBER_EMAIL],
|
|
108
|
+
subscriptionTier: env[constants_js_1.ENV_VARS.SUBSCRIPTION],
|
|
109
|
+
costMultiplierOverride: costMultiplierOverride && !isNaN(costMultiplierOverride) ? costMultiplierOverride : undefined,
|
|
110
|
+
organizationId: env[constants_js_1.ENV_VARS.ORGANIZATION_ID],
|
|
111
|
+
productId: env[constants_js_1.ENV_VARS.PRODUCT_ID],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Checks if the environment variables are currently loaded in the shell.
|
|
120
|
+
*/
|
|
121
|
+
function isEnvLoaded() {
|
|
122
|
+
return (process.env[constants_js_1.ENV_VARS.TELEMETRY_ENABLED] === '1' &&
|
|
123
|
+
!!process.env[constants_js_1.ENV_VARS.OTLP_ENDPOINT]);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Checks if the config file needs migration from old format.
|
|
127
|
+
* Detects: OTEL_LOGS_EXPORTER (should be OTEL_METRICS_EXPORTER)
|
|
128
|
+
*/
|
|
129
|
+
async function checkMigrationStatus() {
|
|
130
|
+
const configPath = getConfigPath();
|
|
131
|
+
const issues = [];
|
|
132
|
+
if (!(0, node_fs_1.existsSync)(configPath)) {
|
|
133
|
+
return { needsMigration: false, issues: [] };
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const content = await (0, promises_1.readFile)(configPath, 'utf-8');
|
|
137
|
+
// Check for old OTEL_LOGS_EXPORTER (should be OTEL_METRICS_EXPORTER)
|
|
138
|
+
if (content.includes('OTEL_LOGS_EXPORTER')) {
|
|
139
|
+
issues.push('Config uses OTEL_LOGS_EXPORTER (should be OTEL_METRICS_EXPORTER)');
|
|
140
|
+
}
|
|
141
|
+
// Check for old endpoint path
|
|
142
|
+
if (content.includes('/meter/v2/ai/otlp')) {
|
|
143
|
+
issues.push('Config uses old endpoint path /meter/v2/ai/otlp (should be /meter/v2/otel)');
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
needsMigration: issues.length > 0,
|
|
147
|
+
issues,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return { needsMigration: false, issues: [] };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Gets the full OTLP endpoint URL from a base URL.
|
|
156
|
+
*/
|
|
157
|
+
function getFullOtlpEndpoint(baseUrl) {
|
|
158
|
+
// Remove trailing slash if present
|
|
159
|
+
const cleanUrl = baseUrl.replace(/\/$/, '');
|
|
160
|
+
return `${cleanUrl}${constants_js_1.OTLP_PATH}`;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/config/loader.ts"],"names":[],"mappings":"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"}
|