@revenium/claude-code-metering 0.1.0 → 0.1.1
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 +22 -28
- package/README.md +321 -139
- package/dist/cli/commands/backfill.d.ts +98 -1
- package/dist/cli/commands/backfill.d.ts.map +1 -1
- package/dist/cli/commands/backfill.js +356 -146
- package/dist/cli/commands/backfill.js.map +1 -1
- package/dist/cli/commands/setup.d.ts +2 -0
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +55 -49
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +2 -11
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/test.d.ts.map +1 -1
- package/dist/cli/commands/test.js +23 -22
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +44 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/core/api/client.d.ts +7 -6
- package/dist/core/api/client.d.ts.map +1 -1
- package/dist/core/api/client.js +52 -47
- package/dist/core/api/client.js.map +1 -1
- package/dist/core/config/loader.d.ts +5 -13
- package/dist/core/config/loader.d.ts.map +1 -1
- package/dist/core/config/loader.js +67 -46
- package/dist/core/config/loader.js.map +1 -1
- package/dist/core/config/validator.d.ts +5 -1
- package/dist/core/config/validator.d.ts.map +1 -1
- package/dist/core/config/validator.js +37 -22
- package/dist/core/config/validator.js.map +1 -1
- package/dist/core/config/writer.d.ts +1 -1
- package/dist/core/config/writer.d.ts.map +1 -1
- package/dist/core/config/writer.js +76 -72
- package/dist/core/config/writer.js.map +1 -1
- package/dist/core/shell/detector.d.ts +8 -1
- package/dist/core/shell/detector.d.ts.map +1 -1
- package/dist/core/shell/detector.js +38 -24
- package/dist/core/shell/detector.js.map +1 -1
- package/dist/core/shell/profile-updater.d.ts +1 -1
- package/dist/core/shell/profile-updater.d.ts.map +1 -1
- package/dist/core/shell/profile-updater.js +40 -27
- package/dist/core/shell/profile-updater.js.map +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +18 -23
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +21 -21
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/hashing.d.ts +18 -0
- package/dist/utils/hashing.d.ts.map +1 -0
- package/dist/utils/hashing.js +27 -0
- package/dist/utils/hashing.js.map +1 -0
- package/package.json +6 -3
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OTLPLogsPayload, OTLPResponse, HealthCheckResult } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
|
-
* Sends an OTLP
|
|
4
|
-
* Posts to /meter/v2/otel/v1/metrics with OTEL Metrics format.
|
|
3
|
+
* Sends an OTLP logs payload to the Revenium endpoint.
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function sendOtlpLogs(baseEndpoint: string, apiKey: string, payload: OTLPLogsPayload): Promise<OTLPResponse>;
|
|
7
6
|
/**
|
|
8
7
|
* Options for creating a test payload.
|
|
9
8
|
*/
|
|
10
9
|
export interface TestPayloadOptions {
|
|
10
|
+
/** Optional subscriber email for attribution */
|
|
11
|
+
email?: string;
|
|
11
12
|
/** Optional organization ID to attribute costs to */
|
|
12
13
|
organizationId?: string;
|
|
13
14
|
/** Optional product ID to attribute costs to */
|
|
14
15
|
productId?: string;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
|
-
* Creates a minimal test
|
|
18
|
+
* Creates a minimal test OTLP logs payload.
|
|
18
19
|
*/
|
|
19
|
-
export declare function createTestPayload(sessionId: string, options?: TestPayloadOptions):
|
|
20
|
+
export declare function createTestPayload(sessionId: string, options?: TestPayloadOptions): OTLPLogsPayload;
|
|
20
21
|
/**
|
|
21
22
|
* Generates a unique session ID for test payloads.
|
|
22
23
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EAClB,MAAM,sBAAsB,CAAC;AAG9B;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,eAAe,CAoEjB;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"}
|
package/dist/core/api/client.js
CHANGED
|
@@ -1,82 +1,87 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.sendOtlpLogs = sendOtlpLogs;
|
|
4
4
|
exports.createTestPayload = createTestPayload;
|
|
5
5
|
exports.generateTestSessionId = generateTestSessionId;
|
|
6
6
|
exports.checkEndpointHealth = checkEndpointHealth;
|
|
7
7
|
const loader_js_1 = require("../config/loader.js");
|
|
8
8
|
/**
|
|
9
|
-
* Sends an OTLP
|
|
10
|
-
* Posts to /meter/v2/otel/v1/metrics with OTEL Metrics format.
|
|
9
|
+
* Sends an OTLP logs payload to the Revenium endpoint.
|
|
11
10
|
*/
|
|
12
|
-
async function
|
|
11
|
+
async function sendOtlpLogs(baseEndpoint, apiKey, payload) {
|
|
13
12
|
const fullEndpoint = (0, loader_js_1.getFullOtlpEndpoint)(baseEndpoint);
|
|
14
|
-
const url = `${fullEndpoint}/v1/
|
|
13
|
+
const url = `${fullEndpoint}/v1/logs`;
|
|
15
14
|
const response = await fetch(url, {
|
|
16
|
-
method:
|
|
15
|
+
method: "POST",
|
|
17
16
|
headers: {
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
"x-api-key": apiKey,
|
|
20
19
|
},
|
|
21
20
|
body: JSON.stringify(payload),
|
|
22
21
|
});
|
|
23
22
|
if (!response.ok) {
|
|
24
23
|
const errorText = await response.text();
|
|
25
|
-
|
|
24
|
+
const safeErrorText = errorText.length > 200 ? errorText.substring(0, 200) + "..." : errorText;
|
|
25
|
+
throw new Error(`OTLP request failed: ${response.status} ${response.statusText} - ${safeErrorText}`);
|
|
26
26
|
}
|
|
27
27
|
return response.json();
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* Creates a minimal test
|
|
30
|
+
* Creates a minimal test OTLP logs payload.
|
|
31
31
|
*/
|
|
32
32
|
function createTestPayload(sessionId, options) {
|
|
33
33
|
const now = Date.now() * 1_000_000; // Convert to nanoseconds
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{ key:
|
|
38
|
-
{ key:
|
|
34
|
+
// Build log record attributes
|
|
35
|
+
// Note: organization.name and product.name go here because ClaudeCodeMapper reads from log record attrs
|
|
36
|
+
const logAttributes = [
|
|
37
|
+
{ key: "session.id", value: { stringValue: sessionId } },
|
|
38
|
+
{ key: "model", value: { stringValue: "cli-connectivity-test" } },
|
|
39
|
+
{ key: "input_tokens", value: { stringValue: "0" } },
|
|
40
|
+
{ key: "output_tokens", value: { stringValue: "0" } },
|
|
41
|
+
{ key: "cache_read_tokens", value: { stringValue: "0" } },
|
|
42
|
+
{ key: "cache_creation_tokens", value: { stringValue: "0" } },
|
|
43
|
+
{ key: "cost_usd", value: { stringValue: "0.0" } },
|
|
44
|
+
{ key: "duration_ms", value: { stringValue: "0" } },
|
|
39
45
|
];
|
|
40
|
-
// Add optional
|
|
46
|
+
// Add optional subscriber/attribution attributes at log record level
|
|
47
|
+
// (backend ClaudeCodeMapper reads these from log record attrs, not resource attrs)
|
|
48
|
+
if (options?.email) {
|
|
49
|
+
logAttributes.push({
|
|
50
|
+
key: "user.email",
|
|
51
|
+
value: { stringValue: options.email },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
41
54
|
if (options?.organizationId) {
|
|
42
|
-
|
|
55
|
+
logAttributes.push({
|
|
56
|
+
key: "organization.name",
|
|
57
|
+
value: { stringValue: options.organizationId },
|
|
58
|
+
});
|
|
43
59
|
}
|
|
44
|
-
// Add optional product ID
|
|
45
60
|
if (options?.productId) {
|
|
46
|
-
|
|
61
|
+
logAttributes.push({
|
|
62
|
+
key: "product.name",
|
|
63
|
+
value: { stringValue: options.productId },
|
|
64
|
+
});
|
|
47
65
|
}
|
|
48
|
-
// Build resource attributes
|
|
49
|
-
const resourceAttributes = [
|
|
50
|
-
{ key: 'service.name', value: { stringValue: 'claude-code' } },
|
|
51
|
-
];
|
|
66
|
+
// Build resource attributes (only service.name needed here)
|
|
67
|
+
const resourceAttributes = [{ key: "service.name", value: { stringValue: "claude-code" } }];
|
|
52
68
|
return {
|
|
53
|
-
|
|
69
|
+
resourceLogs: [
|
|
54
70
|
{
|
|
55
71
|
resource: {
|
|
56
72
|
attributes: resourceAttributes,
|
|
57
73
|
},
|
|
58
|
-
|
|
74
|
+
scopeLogs: [
|
|
59
75
|
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
attributes: commonAttributes,
|
|
66
|
-
timeUnixNano: now.toString(),
|
|
67
|
-
asInt: 0,
|
|
68
|
-
}],
|
|
69
|
-
},
|
|
70
|
-
},
|
|
76
|
+
scope: {
|
|
77
|
+
name: "claude_code",
|
|
78
|
+
version: "0.1.0",
|
|
79
|
+
},
|
|
80
|
+
logRecords: [
|
|
71
81
|
{
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
attributes: commonAttributes,
|
|
76
|
-
timeUnixNano: now.toString(),
|
|
77
|
-
asInt: 0,
|
|
78
|
-
}],
|
|
79
|
-
},
|
|
82
|
+
timeUnixNano: now.toString(),
|
|
83
|
+
body: { stringValue: "claude_code.api_request" },
|
|
84
|
+
attributes: logAttributes,
|
|
80
85
|
},
|
|
81
86
|
],
|
|
82
87
|
},
|
|
@@ -101,18 +106,18 @@ async function checkEndpointHealth(baseEndpoint, apiKey, options) {
|
|
|
101
106
|
try {
|
|
102
107
|
const sessionId = generateTestSessionId();
|
|
103
108
|
const payload = createTestPayload(sessionId, options);
|
|
104
|
-
const response = await
|
|
109
|
+
const response = await sendOtlpLogs(baseEndpoint, apiKey, payload);
|
|
105
110
|
const latencyMs = Date.now() - startTime;
|
|
106
111
|
return {
|
|
107
112
|
healthy: true,
|
|
108
113
|
statusCode: 200,
|
|
109
|
-
message: `Endpoint healthy. Processed ${response.
|
|
114
|
+
message: `Endpoint healthy. Processed ${response.processedEvents} event(s).`,
|
|
110
115
|
latencyMs,
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
catch (error) {
|
|
114
119
|
const latencyMs = Date.now() - startTime;
|
|
115
|
-
const message = error instanceof Error ? error.message :
|
|
120
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
116
121
|
// Try to extract status code from error message
|
|
117
122
|
const statusMatch = message.match(/(\d{3})/);
|
|
118
123
|
const statusCode = statusMatch ? parseInt(statusMatch[1], 10) : undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/core/api/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReveniumConfig } from
|
|
1
|
+
import type { ReveniumConfig } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Gets the path to the Revenium configuration file.
|
|
4
4
|
*/
|
|
@@ -7,6 +7,10 @@ export declare function getConfigPath(): string;
|
|
|
7
7
|
* Checks if the configuration file exists.
|
|
8
8
|
*/
|
|
9
9
|
export declare function configExists(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Parses an .env file content into key-value pairs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnvContent(content: string): Record<string, string>;
|
|
10
14
|
/**
|
|
11
15
|
* Loads the Revenium configuration from the .env file.
|
|
12
16
|
* Returns null if the file doesn't exist.
|
|
@@ -16,18 +20,6 @@ export declare function loadConfig(): Promise<ReveniumConfig | null>;
|
|
|
16
20
|
* Checks if the environment variables are currently loaded in the shell.
|
|
17
21
|
*/
|
|
18
22
|
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
23
|
/**
|
|
32
24
|
* Gets the full OTLP endpoint URL from a base URL.
|
|
33
25
|
*/
|
|
@@ -1 +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;
|
|
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;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2CvE;AA4DD;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAyDjE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAKrC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D"}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getConfigPath = getConfigPath;
|
|
4
4
|
exports.configExists = configExists;
|
|
5
|
+
exports.parseEnvContent = parseEnvContent;
|
|
5
6
|
exports.loadConfig = loadConfig;
|
|
6
7
|
exports.isEnvLoaded = isEnvLoaded;
|
|
7
|
-
exports.checkMigrationStatus = checkMigrationStatus;
|
|
8
8
|
exports.getFullOtlpEndpoint = getFullOtlpEndpoint;
|
|
9
9
|
const node_os_1 = require("node:os");
|
|
10
10
|
const node_path_1 = require("node:path");
|
|
@@ -28,26 +28,33 @@ function configExists() {
|
|
|
28
28
|
*/
|
|
29
29
|
function parseEnvContent(content) {
|
|
30
30
|
const result = {};
|
|
31
|
-
for (const line of content.split(
|
|
31
|
+
for (const line of content.split("\n")) {
|
|
32
32
|
let trimmed = line.trim();
|
|
33
33
|
// Skip empty lines and comments
|
|
34
|
-
if (!trimmed || trimmed.startsWith(
|
|
34
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
35
35
|
continue;
|
|
36
36
|
}
|
|
37
37
|
// Handle 'export' prefix
|
|
38
|
-
if (trimmed.startsWith(
|
|
38
|
+
if (trimmed.startsWith("export ")) {
|
|
39
39
|
trimmed = trimmed.substring(7).trim();
|
|
40
40
|
}
|
|
41
|
-
const equalsIndex = trimmed.indexOf(
|
|
41
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
42
42
|
if (equalsIndex === -1) {
|
|
43
43
|
continue;
|
|
44
44
|
}
|
|
45
45
|
const key = trimmed.substring(0, equalsIndex).trim();
|
|
46
46
|
let value = trimmed.substring(equalsIndex + 1).trim();
|
|
47
|
-
// Remove surrounding quotes if present
|
|
47
|
+
// Remove surrounding quotes if present and unescape
|
|
48
48
|
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
49
49
|
(value.startsWith("'") && value.endsWith("'"))) {
|
|
50
50
|
value = value.substring(1, value.length - 1);
|
|
51
|
+
// Unescape common shell escape sequences
|
|
52
|
+
value = value
|
|
53
|
+
.replace(/\\"/g, '"')
|
|
54
|
+
.replace(/\\'/g, "'")
|
|
55
|
+
.replace(/\\\$/g, "$")
|
|
56
|
+
.replace(/\\`/g, "`")
|
|
57
|
+
.replace(/\\\\/g, "\\");
|
|
51
58
|
}
|
|
52
59
|
result[key] = value;
|
|
53
60
|
}
|
|
@@ -71,8 +78,8 @@ function extractBaseEndpoint(fullEndpoint) {
|
|
|
71
78
|
// Remove the OTLP path suffix to get the base URL
|
|
72
79
|
// Handle both old path (/meter/v2/ai/otlp) and new path (/meter/v2/otlp)
|
|
73
80
|
const path = url.pathname;
|
|
74
|
-
if (path.includes(
|
|
75
|
-
url.pathname =
|
|
81
|
+
if (path.includes("/meter/v2/otlp") || path.includes("/meter/v2/ai/otlp")) {
|
|
82
|
+
url.pathname = "";
|
|
76
83
|
}
|
|
77
84
|
return url.origin;
|
|
78
85
|
}
|
|
@@ -80,6 +87,35 @@ function extractBaseEndpoint(fullEndpoint) {
|
|
|
80
87
|
return fullEndpoint;
|
|
81
88
|
}
|
|
82
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Parses OTEL_RESOURCE_ATTRIBUTES value into key-value pairs.
|
|
92
|
+
* Format: "key1=value1,key2=value2"
|
|
93
|
+
*/
|
|
94
|
+
function parseOtelResourceAttributes(value) {
|
|
95
|
+
const result = {};
|
|
96
|
+
if (!value || typeof value !== "string")
|
|
97
|
+
return result;
|
|
98
|
+
const pairs = value.split(",");
|
|
99
|
+
for (const pair of pairs) {
|
|
100
|
+
const trimmed = pair.trim();
|
|
101
|
+
if (!trimmed)
|
|
102
|
+
continue;
|
|
103
|
+
const equalsIndex = trimmed.indexOf("=");
|
|
104
|
+
if (equalsIndex === -1)
|
|
105
|
+
continue;
|
|
106
|
+
const key = trimmed.substring(0, equalsIndex).trim();
|
|
107
|
+
let attrValue = trimmed.substring(equalsIndex + 1).trim();
|
|
108
|
+
try {
|
|
109
|
+
attrValue = decodeURIComponent(attrValue);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// If decoding fails, use raw value
|
|
113
|
+
}
|
|
114
|
+
if (key)
|
|
115
|
+
result[key] = attrValue;
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
83
119
|
/**
|
|
84
120
|
* Loads the Revenium configuration from the .env file.
|
|
85
121
|
* Returns null if the file doesn't exist.
|
|
@@ -90,25 +126,39 @@ async function loadConfig() {
|
|
|
90
126
|
return null;
|
|
91
127
|
}
|
|
92
128
|
try {
|
|
93
|
-
const content = await (0, promises_1.readFile)(configPath,
|
|
129
|
+
const content = await (0, promises_1.readFile)(configPath, "utf-8");
|
|
94
130
|
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] ||
|
|
131
|
+
const fullEndpoint = env[constants_js_1.ENV_VARS.OTLP_ENDPOINT] || "";
|
|
132
|
+
const headers = env[constants_js_1.ENV_VARS.OTLP_HEADERS] || "";
|
|
97
133
|
const apiKey = extractApiKeyFromHeaders(headers);
|
|
98
134
|
if (!apiKey) {
|
|
99
135
|
return null;
|
|
100
136
|
}
|
|
101
137
|
// Parse cost multiplier override if present
|
|
102
138
|
const costMultiplierStr = env[constants_js_1.ENV_VARS.COST_MULTIPLIER];
|
|
103
|
-
const costMultiplierOverride = costMultiplierStr
|
|
139
|
+
const costMultiplierOverride = costMultiplierStr
|
|
140
|
+
? parseFloat(costMultiplierStr)
|
|
141
|
+
: undefined;
|
|
142
|
+
// Parse OTEL_RESOURCE_ATTRIBUTES for org/product (primary source)
|
|
143
|
+
const resourceAttrsStr = env["OTEL_RESOURCE_ATTRIBUTES"] || "";
|
|
144
|
+
const resourceAttrs = parseOtelResourceAttributes(resourceAttrsStr);
|
|
145
|
+
// Support both .name (preferred) and .id (legacy), with fallback to standalone vars
|
|
146
|
+
const organizationId = resourceAttrs["organization.name"] ||
|
|
147
|
+
resourceAttrs["organization.id"] ||
|
|
148
|
+
env[constants_js_1.ENV_VARS.ORGANIZATION_ID];
|
|
149
|
+
const productId = resourceAttrs["product.name"] ||
|
|
150
|
+
resourceAttrs["product.id"] ||
|
|
151
|
+
env[constants_js_1.ENV_VARS.PRODUCT_ID];
|
|
104
152
|
return {
|
|
105
153
|
apiKey,
|
|
106
154
|
endpoint: extractBaseEndpoint(fullEndpoint),
|
|
107
155
|
email: env[constants_js_1.ENV_VARS.SUBSCRIBER_EMAIL],
|
|
108
156
|
subscriptionTier: env[constants_js_1.ENV_VARS.SUBSCRIPTION],
|
|
109
|
-
costMultiplierOverride: costMultiplierOverride && !isNaN(costMultiplierOverride)
|
|
110
|
-
|
|
111
|
-
|
|
157
|
+
costMultiplierOverride: costMultiplierOverride !== undefined && !isNaN(costMultiplierOverride)
|
|
158
|
+
? costMultiplierOverride
|
|
159
|
+
: undefined,
|
|
160
|
+
organizationId,
|
|
161
|
+
productId,
|
|
112
162
|
};
|
|
113
163
|
}
|
|
114
164
|
catch {
|
|
@@ -119,44 +169,15 @@ async function loadConfig() {
|
|
|
119
169
|
* Checks if the environment variables are currently loaded in the shell.
|
|
120
170
|
*/
|
|
121
171
|
function isEnvLoaded() {
|
|
122
|
-
return (process.env[constants_js_1.ENV_VARS.TELEMETRY_ENABLED] ===
|
|
172
|
+
return (process.env[constants_js_1.ENV_VARS.TELEMETRY_ENABLED] === "1" &&
|
|
123
173
|
!!process.env[constants_js_1.ENV_VARS.OTLP_ENDPOINT]);
|
|
124
174
|
}
|
|
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
175
|
/**
|
|
155
176
|
* Gets the full OTLP endpoint URL from a base URL.
|
|
156
177
|
*/
|
|
157
178
|
function getFullOtlpEndpoint(baseUrl) {
|
|
158
179
|
// Remove trailing slash if present
|
|
159
|
-
const cleanUrl = baseUrl.replace(/\/$/,
|
|
180
|
+
const cleanUrl = baseUrl.replace(/\/$/, "");
|
|
160
181
|
return `${cleanUrl}${constants_js_1.OTLP_PATH}`;
|
|
161
182
|
}
|
|
162
183
|
//# sourceMappingURL=loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/config/loader.ts"],"names":[],"mappings":";;AAgBA,sCAEC;AAKD,oCAEC;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReveniumConfig, ValidationResult } from
|
|
1
|
+
import type { ReveniumConfig, ValidationResult } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Validates that an API key has the correct format.
|
|
4
4
|
* Valid format: hak_{tenant}_{random}
|
|
@@ -12,6 +12,10 @@ export declare function validateEmail(email: string): ValidationResult;
|
|
|
12
12
|
* Validates a subscription tier.
|
|
13
13
|
*/
|
|
14
14
|
export declare function validateSubscriptionTier(tier: string): ValidationResult;
|
|
15
|
+
/**
|
|
16
|
+
* Validates an endpoint URL and ensures it uses HTTPS.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateEndpointUrl(endpoint: string): ValidationResult;
|
|
15
19
|
/**
|
|
16
20
|
* Validates a complete Revenium configuration.
|
|
17
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/config/validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/core/config/validator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CA2B/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAiB7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAmBvE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAuBtE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAC9B,gBAAgB,CAqBlB"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.validateApiKey = validateApiKey;
|
|
4
4
|
exports.validateEmail = validateEmail;
|
|
5
5
|
exports.validateSubscriptionTier = validateSubscriptionTier;
|
|
6
|
+
exports.validateEndpointUrl = validateEndpointUrl;
|
|
6
7
|
exports.validateConfig = validateConfig;
|
|
7
8
|
const constants_js_1 = require("../../utils/constants.js");
|
|
8
9
|
const VALID_TIERS = Object.keys(constants_js_1.SUBSCRIPTION_TIER_CONFIG);
|
|
@@ -12,21 +13,21 @@ const VALID_TIERS = Object.keys(constants_js_1.SUBSCRIPTION_TIER_CONFIG);
|
|
|
12
13
|
*/
|
|
13
14
|
function validateApiKey(apiKey) {
|
|
14
15
|
const errors = [];
|
|
15
|
-
if (!apiKey || apiKey.trim() ===
|
|
16
|
-
errors.push(
|
|
16
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
17
|
+
errors.push("API key is required");
|
|
17
18
|
return { valid: false, errors };
|
|
18
19
|
}
|
|
19
20
|
if (!apiKey.startsWith(constants_js_1.API_KEY_PREFIX)) {
|
|
20
21
|
errors.push(`API key must start with "${constants_js_1.API_KEY_PREFIX}"`);
|
|
21
22
|
}
|
|
22
23
|
// Check for at least two underscores (hak_tenant_random)
|
|
23
|
-
const parts = apiKey.split(
|
|
24
|
+
const parts = apiKey.split("_");
|
|
24
25
|
if (parts.length < 3) {
|
|
25
|
-
errors.push(
|
|
26
|
+
errors.push("API key format should be: hak_{tenant}_{key}");
|
|
26
27
|
}
|
|
27
28
|
// Minimum length check
|
|
28
29
|
if (apiKey.length < 12) {
|
|
29
|
-
errors.push(
|
|
30
|
+
errors.push("API key appears too short");
|
|
30
31
|
}
|
|
31
32
|
return {
|
|
32
33
|
valid: errors.length === 0,
|
|
@@ -38,13 +39,13 @@ function validateApiKey(apiKey) {
|
|
|
38
39
|
*/
|
|
39
40
|
function validateEmail(email) {
|
|
40
41
|
const errors = [];
|
|
41
|
-
if (!email || email.trim() ===
|
|
42
|
+
if (!email || email.trim() === "") {
|
|
42
43
|
// Email is optional
|
|
43
44
|
return { valid: true, errors: [] };
|
|
44
45
|
}
|
|
45
46
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
46
47
|
if (!emailRegex.test(email)) {
|
|
47
|
-
errors.push(
|
|
48
|
+
errors.push("Invalid email format");
|
|
48
49
|
}
|
|
49
50
|
return {
|
|
50
51
|
valid: errors.length === 0,
|
|
@@ -56,13 +57,36 @@ function validateEmail(email) {
|
|
|
56
57
|
*/
|
|
57
58
|
function validateSubscriptionTier(tier) {
|
|
58
59
|
const errors = [];
|
|
59
|
-
if (!tier || tier.trim() ===
|
|
60
|
+
if (!tier || tier.trim() === "") {
|
|
60
61
|
// Tier is optional
|
|
61
62
|
return { valid: true, errors: [] };
|
|
62
63
|
}
|
|
63
64
|
const lowerTier = tier.toLowerCase();
|
|
64
65
|
if (!VALID_TIERS.includes(lowerTier)) {
|
|
65
|
-
errors.push(`Invalid subscription tier. Valid options: ${VALID_TIERS.join(
|
|
66
|
+
errors.push(`Invalid subscription tier. Valid options: ${VALID_TIERS.join(", ")}`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
valid: errors.length === 0,
|
|
70
|
+
errors,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validates an endpoint URL and ensures it uses HTTPS.
|
|
75
|
+
*/
|
|
76
|
+
function validateEndpointUrl(endpoint) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
if (!endpoint || endpoint.trim() === "") {
|
|
79
|
+
errors.push("Endpoint URL is required");
|
|
80
|
+
return { valid: false, errors };
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const url = new URL(endpoint);
|
|
84
|
+
if (url.protocol !== "https:") {
|
|
85
|
+
errors.push("Insecure endpoint: HTTPS is required. Only HTTPS endpoints are allowed.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
errors.push("Invalid endpoint URL format");
|
|
66
90
|
}
|
|
67
91
|
return {
|
|
68
92
|
valid: errors.length === 0,
|
|
@@ -74,25 +98,16 @@ function validateSubscriptionTier(tier) {
|
|
|
74
98
|
*/
|
|
75
99
|
function validateConfig(config) {
|
|
76
100
|
const allErrors = [];
|
|
77
|
-
const apiKeyResult = validateApiKey(config.apiKey ||
|
|
101
|
+
const apiKeyResult = validateApiKey(config.apiKey || "");
|
|
78
102
|
allErrors.push(...apiKeyResult.errors);
|
|
79
|
-
const emailResult = validateEmail(config.email ||
|
|
103
|
+
const emailResult = validateEmail(config.email || "");
|
|
80
104
|
allErrors.push(...emailResult.errors);
|
|
81
105
|
if (config.subscriptionTier) {
|
|
82
106
|
const tierResult = validateSubscriptionTier(config.subscriptionTier);
|
|
83
107
|
allErrors.push(...tierResult.errors);
|
|
84
108
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
try {
|
|
90
|
-
new URL(config.endpoint);
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
allErrors.push('Invalid endpoint URL format');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
109
|
+
const endpointResult = validateEndpointUrl(config.endpoint || "");
|
|
110
|
+
allErrors.push(...endpointResult.errors);
|
|
96
111
|
return {
|
|
97
112
|
valid: allErrors.length === 0,
|
|
98
113
|
errors: allErrors,
|