@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +21 -0
  3. package/README.md +274 -0
  4. package/dist/cli/commands/backfill.d.ts +11 -0
  5. package/dist/cli/commands/backfill.d.ts.map +1 -0
  6. package/dist/cli/commands/backfill.js +390 -0
  7. package/dist/cli/commands/backfill.js.map +1 -0
  8. package/dist/cli/commands/setup.d.ts +13 -0
  9. package/dist/cli/commands/setup.d.ts.map +1 -0
  10. package/dist/cli/commands/setup.js +177 -0
  11. package/dist/cli/commands/setup.js.map +1 -0
  12. package/dist/cli/commands/status.d.ts +5 -0
  13. package/dist/cli/commands/status.d.ts.map +1 -0
  14. package/dist/cli/commands/status.js +95 -0
  15. package/dist/cli/commands/status.js.map +1 -0
  16. package/dist/cli/commands/test.d.ts +9 -0
  17. package/dist/cli/commands/test.d.ts.map +1 -0
  18. package/dist/cli/commands/test.js +67 -0
  19. package/dist/cli/commands/test.js.map +1 -0
  20. package/dist/cli/index.d.ts +3 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +65 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/core/api/client.d.ts +28 -0
  25. package/dist/core/api/client.d.ts.map +1 -0
  26. package/dist/core/api/client.js +127 -0
  27. package/dist/core/api/client.js.map +1 -0
  28. package/dist/core/config/loader.d.ts +35 -0
  29. package/dist/core/config/loader.d.ts.map +1 -0
  30. package/dist/core/config/loader.js +162 -0
  31. package/dist/core/config/loader.js.map +1 -0
  32. package/dist/core/config/validator.d.ts +19 -0
  33. package/dist/core/config/validator.d.ts.map +1 -0
  34. package/dist/core/config/validator.js +101 -0
  35. package/dist/core/config/validator.js.map +1 -0
  36. package/dist/core/config/writer.d.ts +11 -0
  37. package/dist/core/config/writer.d.ts.map +1 -0
  38. package/dist/core/config/writer.js +145 -0
  39. package/dist/core/config/writer.js.map +1 -0
  40. package/dist/core/shell/detector.d.ts +14 -0
  41. package/dist/core/shell/detector.d.ts.map +1 -0
  42. package/dist/core/shell/detector.js +69 -0
  43. package/dist/core/shell/detector.js.map +1 -0
  44. package/dist/core/shell/profile-updater.d.ts +11 -0
  45. package/dist/core/shell/profile-updater.d.ts.map +1 -0
  46. package/dist/core/shell/profile-updater.js +101 -0
  47. package/dist/core/shell/profile-updater.js.map +1 -0
  48. package/dist/index.d.ts +9 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +26 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/types/index.d.ts +96 -0
  53. package/dist/types/index.d.ts.map +1 -0
  54. package/dist/types/index.js +3 -0
  55. package/dist/types/index.js.map +1 -0
  56. package/dist/utils/constants.d.ts +68 -0
  57. package/dist/utils/constants.d.ts.map +1 -0
  58. package/dist/utils/constants.js +73 -0
  59. package/dist/utils/constants.js.map +1 -0
  60. package/dist/utils/masking.d.ts +14 -0
  61. package/dist/utils/masking.d.ts.map +1 -0
  62. package/dist/utils/masking.js +33 -0
  63. package/dist/utils/masking.js.map +1 -0
  64. 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,9 @@
1
+ interface TestOptions {
2
+ verbose?: boolean;
3
+ }
4
+ /**
5
+ * Sends a test metric to verify the integration.
6
+ */
7
+ export declare function testCommand(options?: TestOptions): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=test.d.ts.map
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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":"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"}
@@ -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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"}