@revenium/anthropic 1.0.7 → 1.0.8

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 CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.0.8] - 2025-11-07
6
+
7
+ ### Fixed
8
+ - Fixed `anthropicApiKey` configuration parameter to honor config value before environment variable
9
+ - Fixed `failSilent=false` configuration to properly propagate tracking errors
10
+ - Fixed `maxRetries=0` handling to allow zero retries when explicitly configured
11
+
12
+ ### Added
13
+ - Added `timeToFirstToken` metric tracking for streaming requests
14
+ - Added custom metadata field preservation beyond standard fields
15
+ - Added website link (www.revenium.ai) to README Support section
16
+
17
+ ### Changed
18
+ - Updated Revenium API base URL from `api.revenium.io` to `api.revenium.ai`
19
+ - Updated Node.js requirement from 16+ to 18+
20
+ - Updated `.gitignore` to exclude `dist/` directory and `.env.test`
21
+ - Excluded `.claude/` directory and `*.log` files from npm package
22
+ - Removed `package-lock.json` from public repository allowlist
23
+
5
24
  ## [1.0.7] - 2025-10-25
6
25
 
7
26
  ### Changed
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@revenium/anthropic.svg)](https://www.npmjs.com/package/@revenium/anthropic)
4
4
  [![Node Versions](https://img.shields.io/node/v/@revenium/anthropic.svg)](https://www.npmjs.com/package/@revenium/anthropic)
5
5
  [![Documentation](https://img.shields.io/badge/docs-revenium.io-blue)](https://docs.revenium.io)
6
+ [![Website](https://img.shields.io/badge/website-revenium.ai-blue)](https://www.revenium.ai)
6
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
8
 
8
9
  Automatically track and meter your Anthropic Claude API usage with Revenium. This middleware provides seamless integration with **Anthropic Claude SDK**, requiring minimal code changes and featuring native TypeScript support.
@@ -45,7 +46,7 @@ REVENIUM_METERING_API_KEY="hak_your_revenium_key"
45
46
  ANTHROPIC_API_KEY="sk-ant-your_anthropic_key"
46
47
  ```
47
48
 
48
- > **Note**: `REVENIUM_METERING_BASE_URL` defaults to `https://api.revenium.io` and doesn't need to be set unless using a different environment.
49
+ > **Note**: `REVENIUM_METERING_BASE_URL` defaults to `https://api.revenium.ai` and doesn't need to be set unless using a different environment.
49
50
 
50
51
  ### 3. Run Your First Example
51
52
 
@@ -132,6 +133,48 @@ Add business context to track usage by organization, user, task type, or custom
132
133
  | `agent` | AI agent or bot identifier | Distinguish between multiple AI agents or automation workflows in your system |
133
134
  | `responseQualityScore` | Custom quality rating (0.0-1.0) | Track user satisfaction or automated quality metrics for model performance analysis |
134
135
 
136
+ **All metadata fields are optional.** Custom fields beyond the standard ones are automatically preserved and sent to Revenium.
137
+
138
+ **Resources:**
139
+ - [examples/advanced-features.ts](https://github.com/revenium/revenium-middleware-anthropic-node/blob/HEAD/examples/advanced-features.ts) - Working examples
140
+
141
+ ## Metadata Fields
142
+
143
+ The middleware automatically sends the following fields to Revenium's `/meter/v2/ai/completions` endpoint:
144
+
145
+ | Field | Type | Source | Description |
146
+ |-------|------|--------|-------------|
147
+ | `stopReason` | string | Anthropic Response | Why completion stopped: "END", "MAX_TOKENS", "STOP_SEQUENCE", "TOOL_USE" |
148
+ | `costType` | string | Fixed | Always "AI" for AI completions |
149
+ | `isStreamed` | boolean | Request Type | Whether response was streamed |
150
+ | `taskType` | string | usageMetadata | Optional task categorization |
151
+ | `agent` | string | usageMetadata | Optional agent identifier |
152
+ | `operationType` | string | Fixed | Always "CHAT" for message completions |
153
+ | `inputTokenCount` | number | Anthropic Usage | Input tokens consumed |
154
+ | `outputTokenCount` | number | Anthropic Usage | Output tokens generated |
155
+ | `reasoningTokenCount` | number | Fixed | Always 0 (Anthropic doesn't report reasoning tokens) |
156
+ | `cacheCreationTokenCount` | number | Anthropic Usage | Tokens used for prompt caching creation |
157
+ | `cacheReadTokenCount` | number | Anthropic Usage | Tokens read from prompt cache |
158
+ | `totalTokenCount` | number | Calculated | Sum of input + output tokens |
159
+ | `organizationId` | string | usageMetadata | Optional organization identifier |
160
+ | `productId` | string | usageMetadata | Optional product identifier |
161
+ | `subscriber` | object | usageMetadata | Optional subscriber info (id, email, credential) |
162
+ | `subscriptionId` | string | usageMetadata | Optional subscription plan identifier |
163
+ | `model` | string | Request | Anthropic model used (e.g., "claude-3-5-haiku-20241022") |
164
+ | `transactionId` | string | Generated | Unique request identifier (UUID) |
165
+ | `responseTime` | string | Timestamp | ISO 8601 timestamp of response completion |
166
+ | `requestDuration` | number | Measured | Total request duration in milliseconds |
167
+ | `provider` | string | Fixed | Always "Anthropic" |
168
+ | `requestTime` | string | Timestamp | ISO 8601 timestamp when request started |
169
+ | `completionStartTime` | string | Timestamp | ISO 8601 timestamp when completion generation started |
170
+ | `timeToFirstToken` | number | Measured | Milliseconds from request start to first token (streaming only) |
171
+ | `traceId` | string | usageMetadata | Optional trace identifier for request correlation |
172
+ | `responseQualityScore` | number | usageMetadata | Optional quality rating (0.0-1.0) |
173
+ | `middlewareSource` | string | Fixed | Always "nodejs" to identify this middleware |
174
+ | Custom Fields | any | usageMetadata | Any additional fields in usageMetadata are preserved |
175
+
176
+ **Note:** Fields marked as "usageMetadata" come from the optional `usageMetadata` object you pass to `messages.create()`.
177
+
135
178
  **Resources:**
136
179
  - [API Reference](https://revenium.readme.io/reference/meter_ai_completion) - Complete metadata field documentation
137
180
 
@@ -143,7 +186,7 @@ Add business context to track usage by organization, user, task type, or custom
143
186
  | ---------------------------- | -------- | -------------------------- | --------------------------------- |
144
187
  | `REVENIUM_METERING_API_KEY` | Yes | - | Your Revenium API key |
145
188
  | `ANTHROPIC_API_KEY` | Yes | - | Anthropic Claude API key |
146
- | `REVENIUM_METERING_BASE_URL` | No | `https://api.revenium.io` | Revenium metering API base URL |
189
+ | `REVENIUM_METERING_BASE_URL` | No | `https://api.revenium.ai` | Revenium metering API base URL |
147
190
  | `REVENIUM_DEBUG` | No | `false` | Enable debug logging (true/false) |
148
191
 
149
192
  ### Manual Configuration
@@ -234,7 +277,9 @@ The middleware never blocks your application - if Revenium tracking fails, your
234
277
 
235
278
  ## Documentation
236
279
 
237
- For detailed documentation, visit [docs.revenium.io](https://docs.revenium.io)
280
+ For detailed documentation, visit [docs.revenium.io](https://docs.revenium.io).
281
+ For contributor lifecycle, validation, and provider metadata, see
282
+ [docs/standardization/README.md](https://github.com/revenium/revenium-middleware-anthropic-node/blob/HEAD/docs/standardization/README.md).
238
283
 
239
284
  ## Contributing
240
285
 
@@ -256,6 +301,7 @@ This project is licensed under the MIT License - see the [LICENSE](https://githu
256
301
 
257
302
  For issues, feature requests, or contributions:
258
303
 
304
+ - **Website**: [www.revenium.ai](https://www.revenium.ai)
259
305
  - **GitHub Repository**: [revenium/revenium-middleware-anthropic-node](https://github.com/revenium/revenium-middleware-anthropic-node)
260
306
  - **Issues**: [Report bugs or request features](https://github.com/revenium/revenium-middleware-anthropic-node/issues)
261
307
  - **Documentation**: [docs.revenium.io](https://docs.revenium.io)
@@ -10,7 +10,7 @@ exports.ANTHROPIC_PATTERNS = exports.API_ENDPOINTS = exports.ENV_VARS = exports.
10
10
  */
11
11
  exports.DEFAULT_CONFIG = {
12
12
  /** Default Revenium API base URL */
13
- REVENIUM_BASE_URL: 'https://api.revenium.io',
13
+ REVENIUM_BASE_URL: 'https://api.revenium.ai',
14
14
  /** Default API timeout in milliseconds */
15
15
  API_TIMEOUT: 5000,
16
16
  /** Default maximum retries for failed API calls */
@@ -92,7 +92,7 @@ async function sendReveniumMetrics(data) {
92
92
  duration: data.duration,
93
93
  });
94
94
  return response;
95
- }, config.maxRetries || constants_1.DEFAULT_CONFIG.MAX_RETRIES);
95
+ }, config.maxRetries ?? constants_1.DEFAULT_CONFIG.MAX_RETRIES);
96
96
  });
97
97
  }
98
98
  catch (error) {
@@ -102,8 +102,12 @@ async function sendReveniumMetrics(data) {
102
102
  .withDuration(data.duration)
103
103
  .build();
104
104
  (0, error_handling_1.handleError)(error, logger, errorContext);
105
- // Always fail silently for tracking errors to prevent breaking user's application
106
- // Tracking errors should never break the user's main application flow
105
+ // Respect failSilent configuration
106
+ // By default (failSilent=true), tracking errors don't break the user's application
107
+ // If failSilent=false, re-throw the error for user handling
108
+ if (config.failSilent === false) {
109
+ throw error;
110
+ }
107
111
  }
108
112
  finally {
109
113
  clearTimeout(timeoutId);
@@ -116,6 +120,20 @@ function buildReveniumPayload(data) {
116
120
  const now = new Date().toISOString();
117
121
  const requestTime = data.requestTime.toISOString();
118
122
  const completionStartTime = data.responseTime.toISOString();
123
+ // Standard known fields
124
+ const knownFields = new Set([
125
+ 'taskType', 'agent', 'organizationId', 'productId', 'subscriber',
126
+ 'subscriptionId', 'traceId', 'responseQualityScore'
127
+ ]);
128
+ // Extract custom fields (anything NOT in the standard 8 fields)
129
+ const customFields = {};
130
+ if (data.metadata) {
131
+ for (const [key, value] of Object.entries(data.metadata)) {
132
+ if (!knownFields.has(key)) {
133
+ customFields[key] = value;
134
+ }
135
+ }
136
+ }
119
137
  return {
120
138
  stopReason: getStopReason(data.stopReason),
121
139
  costType: "AI",
@@ -144,6 +162,7 @@ function buildReveniumPayload(data) {
144
162
  traceId: data.metadata?.traceId,
145
163
  responseQualityScore: data.metadata?.responseQualityScore, // Fixed: Now sending to Revenium
146
164
  middlewareSource: "nodejs",
165
+ ...customFields, // Preserve any custom metadata fields
147
166
  };
148
167
  }
149
168
  /**
@@ -184,6 +203,12 @@ function trackUsageAsync(trackingData) {
184
203
  requestId: trackingData.requestId,
185
204
  context: errorContext,
186
205
  });
206
+ // If failSilent=false, propagate the error
207
+ // Note: Since this is fire-and-forget, the error won't be caught by caller
208
+ // but it will appear as an unhandled promise rejection
209
+ if (config.failSilent === false) {
210
+ throw error;
211
+ }
187
212
  });
188
213
  }
189
214
  /**
@@ -160,17 +160,17 @@ function validateReveniumConfig(config) {
160
160
  }
161
161
  catch {
162
162
  errors.push('reveniumBaseUrl must be a valid URL');
163
- suggestions.push('Use format: https://api.revenium.io');
163
+ suggestions.push('Use format: https://api.revenium.ai');
164
164
  }
165
165
  }
166
166
  // Validate optional Anthropic API key
167
- if (!isString(cfg?.anthropicApiKey)) {
167
+ if (cfg?.anthropicApiKey !== undefined && !isString(cfg?.anthropicApiKey)) {
168
168
  errors.push('anthropicApiKey must be a string if provided');
169
169
  }
170
- else if (cfg?.anthropicApiKey?.trim()?.length === 0) {
170
+ else if (cfg?.anthropicApiKey !== undefined && cfg?.anthropicApiKey?.trim()?.length === 0) {
171
171
  warnings.push('anthropicApiKey is empty - API calls may fail');
172
172
  }
173
- else if (!cfg?.anthropicApiKey?.startsWith(constants_1.VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
173
+ else if (cfg?.anthropicApiKey && !cfg?.anthropicApiKey?.startsWith(constants_1.VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
174
174
  warnings.push(`anthropicApiKey does not start with "${constants_1.VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX}" - verify it is correct`);
175
175
  }
176
176
  // Validate optional timeout using constants
@@ -42,9 +42,12 @@ function getMessagesPrototype() {
42
42
  return anthropicConstructor?._Messages?.prototype;
43
43
  // Method 3: Create a minimal instance with the real API key if available
44
44
  // Fallback approach when direct prototype access methods fail
45
- const apiKey = process.env.ANTHROPIC_API_KEY;
45
+ // Check config first, then environment variable
46
+ const config = (0, config_1.getConfig)();
47
+ const apiKey = config?.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
46
48
  if (!apiKey) {
47
- throw new error_handling_1.AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed');
49
+ throw new error_handling_1.AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed. ' +
50
+ 'Provide ANTHROPIC_API_KEY environment variable or pass anthropicApiKey in config.');
48
51
  }
49
52
  const minimalInstance = new sdk_1.default({ apiKey });
50
53
  const messagesPrototype = Object.getPrototypeOf(minimalInstance.messages);
@@ -155,10 +158,12 @@ async function handleStreamingResponse(stream, context) {
155
158
  const endTime = Date.now();
156
159
  const responseTime = new Date();
157
160
  const duration = endTime - startTime;
161
+ const timeToFirstToken = firstTokenTime ? firstTokenTime - startTime : undefined;
158
162
  logger.debug('Stream completed, extracting usage', {
159
163
  requestId,
160
164
  chunkCount: chunks.length,
161
- duration
165
+ duration,
166
+ timeToFirstToken
162
167
  });
163
168
  const usage = (0, tracking_1.extractUsageFromStream)(chunks);
164
169
  // Create tracking data
@@ -174,7 +179,8 @@ async function handleStreamingResponse(stream, context) {
174
179
  stopReason: usage.stopReason,
175
180
  metadata,
176
181
  requestTime,
177
- responseTime
182
+ responseTime,
183
+ timeToFirstToken
178
184
  };
179
185
  // Track usage asynchronously
180
186
  (0, tracking_1.trackUsageAsync)(trackingData);
@@ -7,7 +7,7 @@
7
7
  */
8
8
  export const DEFAULT_CONFIG = {
9
9
  /** Default Revenium API base URL */
10
- REVENIUM_BASE_URL: 'https://api.revenium.io',
10
+ REVENIUM_BASE_URL: 'https://api.revenium.ai',
11
11
  /** Default API timeout in milliseconds */
12
12
  API_TIMEOUT: 5000,
13
13
  /** Default maximum retries for failed API calls */
@@ -83,7 +83,7 @@ export async function sendReveniumMetrics(data) {
83
83
  duration: data.duration,
84
84
  });
85
85
  return response;
86
- }, config.maxRetries || DEFAULT_CONFIG.MAX_RETRIES);
86
+ }, config.maxRetries ?? DEFAULT_CONFIG.MAX_RETRIES);
87
87
  });
88
88
  }
89
89
  catch (error) {
@@ -93,8 +93,12 @@ export async function sendReveniumMetrics(data) {
93
93
  .withDuration(data.duration)
94
94
  .build();
95
95
  handleError(error, logger, errorContext);
96
- // Always fail silently for tracking errors to prevent breaking user's application
97
- // Tracking errors should never break the user's main application flow
96
+ // Respect failSilent configuration
97
+ // By default (failSilent=true), tracking errors don't break the user's application
98
+ // If failSilent=false, re-throw the error for user handling
99
+ if (config.failSilent === false) {
100
+ throw error;
101
+ }
98
102
  }
99
103
  finally {
100
104
  clearTimeout(timeoutId);
@@ -107,6 +111,20 @@ function buildReveniumPayload(data) {
107
111
  const now = new Date().toISOString();
108
112
  const requestTime = data.requestTime.toISOString();
109
113
  const completionStartTime = data.responseTime.toISOString();
114
+ // Standard known fields
115
+ const knownFields = new Set([
116
+ 'taskType', 'agent', 'organizationId', 'productId', 'subscriber',
117
+ 'subscriptionId', 'traceId', 'responseQualityScore'
118
+ ]);
119
+ // Extract custom fields (anything NOT in the standard 8 fields)
120
+ const customFields = {};
121
+ if (data.metadata) {
122
+ for (const [key, value] of Object.entries(data.metadata)) {
123
+ if (!knownFields.has(key)) {
124
+ customFields[key] = value;
125
+ }
126
+ }
127
+ }
110
128
  return {
111
129
  stopReason: getStopReason(data.stopReason),
112
130
  costType: "AI",
@@ -135,6 +153,7 @@ function buildReveniumPayload(data) {
135
153
  traceId: data.metadata?.traceId,
136
154
  responseQualityScore: data.metadata?.responseQualityScore, // Fixed: Now sending to Revenium
137
155
  middlewareSource: "nodejs",
156
+ ...customFields, // Preserve any custom metadata fields
138
157
  };
139
158
  }
140
159
  /**
@@ -175,6 +194,12 @@ export function trackUsageAsync(trackingData) {
175
194
  requestId: trackingData.requestId,
176
195
  context: errorContext,
177
196
  });
197
+ // If failSilent=false, propagate the error
198
+ // Note: Since this is fire-and-forget, the error won't be caught by caller
199
+ // but it will appear as an unhandled promise rejection
200
+ if (config.failSilent === false) {
201
+ throw error;
202
+ }
178
203
  });
179
204
  }
180
205
  /**
@@ -149,17 +149,17 @@ export function validateReveniumConfig(config) {
149
149
  }
150
150
  catch {
151
151
  errors.push('reveniumBaseUrl must be a valid URL');
152
- suggestions.push('Use format: https://api.revenium.io');
152
+ suggestions.push('Use format: https://api.revenium.ai');
153
153
  }
154
154
  }
155
155
  // Validate optional Anthropic API key
156
- if (!isString(cfg?.anthropicApiKey)) {
156
+ if (cfg?.anthropicApiKey !== undefined && !isString(cfg?.anthropicApiKey)) {
157
157
  errors.push('anthropicApiKey must be a string if provided');
158
158
  }
159
- else if (cfg?.anthropicApiKey?.trim()?.length === 0) {
159
+ else if (cfg?.anthropicApiKey !== undefined && cfg?.anthropicApiKey?.trim()?.length === 0) {
160
160
  warnings.push('anthropicApiKey is empty - API calls may fail');
161
161
  }
162
- else if (!cfg?.anthropicApiKey?.startsWith(VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
162
+ else if (cfg?.anthropicApiKey && !cfg?.anthropicApiKey?.startsWith(VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX)) {
163
163
  warnings.push(`anthropicApiKey does not start with "${VALIDATION_CONFIG.ANTHROPIC_API_KEY_PREFIX}" - verify it is correct`);
164
164
  }
165
165
  // Validate optional timeout using constants
@@ -2,7 +2,7 @@
2
2
  * Anthropic SDK wrapper with type safety and structured error handling
3
3
  */
4
4
  import Anthropic from '@anthropic-ai/sdk';
5
- import { getLogger } from './config.js';
5
+ import { getLogger, getConfig } from './config.js';
6
6
  import { trackUsageAsync, extractUsageFromResponse, extractUsageFromStream } from './tracking.js';
7
7
  import { validateAnthropicMessageParams, validateUsageMetadata } from './utils/validation.js';
8
8
  import { AnthropicPatchingError, RequestProcessingError, StreamProcessingError, createErrorContext, handleError } from './utils/error-handling.js';
@@ -34,9 +34,12 @@ function getMessagesPrototype() {
34
34
  return anthropicConstructor?._Messages?.prototype;
35
35
  // Method 3: Create a minimal instance with the real API key if available
36
36
  // Fallback approach when direct prototype access methods fail
37
- const apiKey = process.env.ANTHROPIC_API_KEY;
37
+ // Check config first, then environment variable
38
+ const config = getConfig();
39
+ const apiKey = config?.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY;
38
40
  if (!apiKey) {
39
- throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed');
41
+ throw new AnthropicPatchingError('Unable to access Anthropic Messages prototype: No API key available and direct prototype access failed. ' +
42
+ 'Provide ANTHROPIC_API_KEY environment variable or pass anthropicApiKey in config.');
40
43
  }
41
44
  const minimalInstance = new Anthropic({ apiKey });
42
45
  const messagesPrototype = Object.getPrototypeOf(minimalInstance.messages);
@@ -147,10 +150,12 @@ async function handleStreamingResponse(stream, context) {
147
150
  const endTime = Date.now();
148
151
  const responseTime = new Date();
149
152
  const duration = endTime - startTime;
153
+ const timeToFirstToken = firstTokenTime ? firstTokenTime - startTime : undefined;
150
154
  logger.debug('Stream completed, extracting usage', {
151
155
  requestId,
152
156
  chunkCount: chunks.length,
153
- duration
157
+ duration,
158
+ timeToFirstToken
154
159
  });
155
160
  const usage = extractUsageFromStream(chunks);
156
161
  // Create tracking data
@@ -166,7 +171,8 @@ async function handleStreamingResponse(stream, context) {
166
171
  stopReason: usage.stopReason,
167
172
  metadata,
168
173
  requestTime,
169
- responseTime
174
+ responseTime,
175
+ timeToFirstToken
170
176
  };
171
177
  // Track usage asynchronously
172
178
  trackUsageAsync(trackingData);
@@ -7,7 +7,7 @@
7
7
  */
8
8
  export declare const DEFAULT_CONFIG: {
9
9
  /** Default Revenium API base URL */
10
- readonly REVENIUM_BASE_URL: "https://api.revenium.io";
10
+ readonly REVENIUM_BASE_URL: "https://api.revenium.ai";
11
11
  /** Default API timeout in milliseconds */
12
12
  readonly API_TIMEOUT: 5000;
13
13
  /** Default maximum retries for failed API calls */
@@ -51,9 +51,9 @@ export interface Subscriber {
51
51
  * @example
52
52
  * ```typescript
53
53
  * const config: ReveniumConfig = {
54
- * reveniumApiKey: 'hak_1234567890abcdef',
55
- * reveniumBaseUrl: 'https://api.revenium.io',
56
- * anthropicApiKey: 'sk-ant-1234567890abcdef',
54
+ * reveniumApiKey: 'hak_your_key_value_here',
55
+ * reveniumBaseUrl: 'https://api.revenium.ai',
56
+ * anthropicApiKey: 'sk-ant-your_api_key_here',
57
57
  * apiTimeout: 8000,
58
58
  * failSilent: true,
59
59
  * maxRetries: 3
@@ -32,7 +32,7 @@ REVENIUM_METERING_API_KEY=hak_your_revenium_api_key
32
32
  ANTHROPIC_API_KEY=sk-ant-your_anthropic_api_key
33
33
 
34
34
  # Optional
35
- REVENIUM_METERING_BASE_URL=https://api.revenium.io
35
+ REVENIUM_METERING_BASE_URL=https://api.revenium.ai
36
36
  REVENIUM_DEBUG=false
37
37
  ```
38
38
 
@@ -68,7 +68,7 @@ npx tsx node_modules/@revenium/anthropic/examples/advanced-features.ts
68
68
  The simplest example to get you started with Revenium tracking:
69
69
 
70
70
  - **Minimal setup** - Just import, configure, and start tracking
71
- - **Complete metadata example** - Shows all 11 optional metadata fields
71
+ - **Complete metadata example** - Shows all 8 optional metadata fields
72
72
  - **Ready to customize** - Uncomment the metadata section to add tracking context
73
73
 
74
74
  **Key Features:**
@@ -137,7 +137,7 @@ Ensure your `tsconfig.json` includes:
137
137
 
138
138
  ## Requirements
139
139
 
140
- - **Node.js 16+** with TypeScript support
140
+ - **Node.js 18+** with TypeScript support
141
141
  - **TypeScript 4.5+** for module augmentation features
142
142
  - **Valid Revenium API key** (starts with `hak_`)
143
143
  - **Valid Anthropic API key** (starts with `sk-ant-`)
@@ -432,7 +432,7 @@ function checkEnvironment(): void {
432
432
  console.error(" REVENIUM_METERING_API_KEY=hak_your_api_key");
433
433
  console.error(" ANTHROPIC_API_KEY=sk-ant-your_anthropic_key");
434
434
  console.error("\nOptional (uses defaults if not set):");
435
- console.error(" REVENIUM_METERING_BASE_URL=https://api.revenium.io");
435
+ console.error(" REVENIUM_METERING_BASE_URL=https://api.revenium.ai");
436
436
  console.error(" REVENIUM_DEBUG=true # For detailed logging");
437
437
  process.exit(1);
438
438
  }
@@ -194,7 +194,7 @@ async function demonstrateManualConfiguration() {
194
194
  reveniumApiKey:
195
195
  process.env.REVENIUM_METERING_API_KEY || "hak_your_api_key_here",
196
196
  reveniumBaseUrl:
197
- process.env.REVENIUM_METERING_BASE_URL || "https://api.revenium.io",
197
+ process.env.REVENIUM_METERING_BASE_URL || "https://api.revenium.ai",
198
198
 
199
199
  // Optional: Anthropic API key (can also be set in Anthropic client)
200
200
  anthropicApiKey: process.env.ANTHROPIC_API_KEY,
@@ -279,7 +279,7 @@ function checkEnvironment() {
279
279
  console.error(" REVENIUM_METERING_API_KEY=hak_your_api_key");
280
280
  console.error(" ANTHROPIC_API_KEY=sk-ant-your_anthropic_key");
281
281
  console.error("\nOptional (uses defaults if not set):");
282
- console.error(" REVENIUM_METERING_BASE_URL=https://api.revenium.io");
282
+ console.error(" REVENIUM_METERING_BASE_URL=https://api.revenium.ai");
283
283
  console.error(" REVENIUM_DEBUG=true # For detailed logging");
284
284
  process.exit(1);
285
285
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revenium/anthropic",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Transparent TypeScript middleware for automatic Revenium usage tracking with Anthropic Claude AI",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -73,12 +73,15 @@
73
73
  "dist/esm/**/*.js",
74
74
  "dist/types/**/*.d.ts",
75
75
  "examples/**/*",
76
+ "!examples/.claude/**",
77
+ "!examples/**/*.log",
78
+ "!examples/**/*.sh",
76
79
  "README.md",
77
80
  "CHANGELOG.md",
78
81
  "LICENSE"
79
82
  ],
80
83
  "sideEffects": false,
81
84
  "engines": {
82
- "node": ">=16.0.0"
85
+ "node": ">=18.0.0"
83
86
  }
84
87
  }
@@ -1,24 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Read(//Users/daithi/git/rev/git/revenium-middleware-anthropic-node/**)",
5
- "Bash(npm init:*)",
6
- "Bash(npm install:*)",
7
- "Bash(cp:*)",
8
- "Bash(npx tsx:*)",
9
- "WebFetch(domain:revenium.readme.io)",
10
- "Bash(tee:*)",
11
- "Bash(npm run clean:*)",
12
- "Bash(npm run build:*)",
13
- "Bash(node -e \"require(''@revenium/anthropic''); console.log(''✅ Option A (Auto-init) - Import works'')\")",
14
- "Bash(for section in \"Features\" \"Package Migration\" \"Getting Started\" \"Advanced Usage\" \"Configuration Options\" \"Troubleshooting\" \"Requirements\" \"Documentation\" \"Contributing\" \"Code of Conduct\" \"Security\" \"License\" \"Support\" \"Development\")",
15
- "Bash(do)",
16
- "Bash(echo:*)",
17
- "Bash(done)",
18
- "Bash(grep:*)",
19
- "Bash(gitleaks detect:*)"
20
- ],
21
- "deny": [],
22
- "ask": []
23
- }
24
- }