@lmnr-ai/claude-code-proxy 0.1.1-alpha.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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Laminar Claude Code proxy
2
+
3
+ This library contains a tiny Rust proxy for Claude Code that can accept
4
+ requests from claude-agent-sdk with trace id and span id in order
5
+ to associate spans from the proxy with the parent context.
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Laminar Claude Code Proxy - TypeScript/JavaScript bindings for HTTP proxy server
3
+ */
4
+ export interface SpanContext {
5
+ traceId: string;
6
+ spanId: string;
7
+ projectApiKey: string;
8
+ spanIdsPath?: string[];
9
+ spanPath?: string[];
10
+ laminarUrl?: string;
11
+ }
12
+ /**
13
+ * Set the current trace context by sending an HTTP request to the running proxy server.
14
+ *
15
+ * @param context - The span context containing trace information
16
+ * @throws Error if the HTTP request fails
17
+ */
18
+ export declare function setCurrentTrace(context: SpanContext): Promise<void>;
19
+ /**
20
+ * Run the proxy server in a background thread with health monitoring.
21
+ *
22
+ * A background monitor will check the server health every HEALTH_CHECK_INTERVAL ms
23
+ * and automatically restart it if it dies.
24
+ *
25
+ * @param url - The target URL to proxy requests to
26
+ * @param port - The port to listen on (default: 45667)
27
+ */
28
+ export declare function runServer(url: string, port?: number): void;
29
+ /**
30
+ * Stop the proxy server and its health monitoring.
31
+ */
32
+ export declare function stopServer(): void;
33
+ export declare const run: any, stop: any;
package/dist/index.js ADDED
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ /**
3
+ * Laminar Claude Code Proxy - TypeScript/JavaScript bindings for HTTP proxy server
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stop = exports.run = void 0;
7
+ exports.setCurrentTrace = setCurrentTrace;
8
+ exports.runServer = runServer;
9
+ exports.stopServer = stopServer;
10
+ // Import native functions from the NAPI module
11
+ // When built, this will be in dist/index.js and the native module will be in dist/
12
+ // NAPI-RS generates the binding files in the same directory
13
+ const native = require('./lmnr-claude-code-proxy');
14
+ const HEALTH_CHECK_INTERVAL = 1000;
15
+ // Module-level variables to track the server state
16
+ let serverPort = 45667;
17
+ let targetUrl = '';
18
+ let monitorInterval = null;
19
+ /**
20
+ * Set the current trace context by sending an HTTP request to the running proxy server.
21
+ *
22
+ * @param context - The span context containing trace information
23
+ * @throws Error if the HTTP request fails
24
+ */
25
+ async function setCurrentTrace(context) {
26
+ const { traceId, spanId, projectApiKey, spanIdsPath = [], spanPath = [], laminarUrl = 'https://api.lmnr.ai', } = context;
27
+ // Prepare the JSON payload
28
+ const payload = {
29
+ trace_id: traceId,
30
+ span_id: spanId,
31
+ project_api_key: projectApiKey,
32
+ span_ids_path: spanIdsPath,
33
+ span_path: spanPath,
34
+ laminar_url: laminarUrl,
35
+ };
36
+ // Send POST request to the internal endpoint
37
+ const url = `http://127.0.0.1:${serverPort}/lmnr-internal/span-context`;
38
+ try {
39
+ const response = await fetch(url, {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ },
44
+ body: JSON.stringify(payload),
45
+ });
46
+ if (!response.ok) {
47
+ throw new Error(`HTTP ${response.status}`);
48
+ }
49
+ }
50
+ catch (error) {
51
+ throw new Error(`Failed to set trace context: ${error}`);
52
+ }
53
+ }
54
+ /**
55
+ * Background function that monitors server health and restarts if needed.
56
+ * Polls every HEALTH_CHECK_INTERVAL ms.
57
+ */
58
+ async function healthCheckMonitor() {
59
+ const url = `http://127.0.0.1:${serverPort}/lmnr-internal/health`;
60
+ try {
61
+ const response = await fetch(url, {
62
+ // Force new connection for each health check to avoid interfering with streaming
63
+ headers: {
64
+ 'Connection': 'close'
65
+ },
66
+ });
67
+ if (response.status === 200) {
68
+ // Server is healthy
69
+ return;
70
+ }
71
+ }
72
+ catch (error) {
73
+ // Server is not responding, try to restart
74
+ console.warn(`Server health check failed: ${error}. Attempting to restart...`);
75
+ try {
76
+ // Try to stop the existing server (it might be stuck)
77
+ try {
78
+ native.stop();
79
+ }
80
+ catch {
81
+ // Server might already be dead
82
+ }
83
+ // Wait a bit before restarting
84
+ await new Promise(resolve => setTimeout(resolve, 100));
85
+ // Restart the server
86
+ native.run(targetUrl, serverPort);
87
+ console.info('Server restarted successfully');
88
+ }
89
+ catch (restartError) {
90
+ console.error(`Failed to restart server: ${restartError}`);
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Run the proxy server in a background thread with health monitoring.
96
+ *
97
+ * A background monitor will check the server health every HEALTH_CHECK_INTERVAL ms
98
+ * and automatically restart it if it dies.
99
+ *
100
+ * @param url - The target URL to proxy requests to
101
+ * @param port - The port to listen on (default: 45667)
102
+ */
103
+ function runServer(url, port = 45667) {
104
+ // Stop any existing monitoring
105
+ if (monitorInterval !== null) {
106
+ clearInterval(monitorInterval);
107
+ monitorInterval = null;
108
+ }
109
+ // Store server configuration
110
+ serverPort = port;
111
+ targetUrl = url;
112
+ // Start the server
113
+ try {
114
+ native.run(url, port);
115
+ }
116
+ catch (error) {
117
+ console.error(`Error running the proxy server: ${error}`);
118
+ throw error;
119
+ }
120
+ // Start the health check monitor
121
+ monitorInterval = setInterval(() => {
122
+ healthCheckMonitor().catch(() => { });
123
+ }, HEALTH_CHECK_INTERVAL);
124
+ }
125
+ /**
126
+ * Stop the proxy server and its health monitoring.
127
+ */
128
+ function stopServer() {
129
+ // Stop the monitor
130
+ if (monitorInterval !== null) {
131
+ clearInterval(monitorInterval);
132
+ monitorInterval = null;
133
+ }
134
+ // Stop the server
135
+ try {
136
+ native.stop();
137
+ }
138
+ catch { }
139
+ }
140
+ // Re-export native functions for direct access if needed
141
+ exports.run = native.run, exports.stop = native.stop;
Binary file
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@lmnr-ai/claude-code-proxy",
3
+ "version": "0.1.1-alpha.1",
4
+ "description": "HTTP proxy for Claude Desktop API requests with Laminar observability",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "napi": {
8
+ "binaryName": "lmnr-claude-code-proxy",
9
+ "package": {
10
+ "name": "@lmnr-ai/claude-code-proxy"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "keywords": [
17
+ "claude",
18
+ "proxy",
19
+ "anthropic",
20
+ "laminar",
21
+ "observability",
22
+ "napi"
23
+ ],
24
+ "author": "Laminar AI",
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "@napi-rs/cli": "^3.0.0",
28
+ "@types/node": "^22.0.0",
29
+ "ts-node": "^10.9.0",
30
+ "typescript": "^5.6.0"
31
+ },
32
+ "dependencies": {},
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "scripts": {
37
+ "artifacts": "napi artifacts",
38
+ "build:cargo": "cd ../bin && cargo build --release --features typescript",
39
+ "build:napi": "cd ../bin && napi build --platform --release -o ../ts/dist",
40
+ "build:ts": "tsc",
41
+ "build": "node scripts/build.js",
42
+ "test": "echo \"Error: no test specified\" && exit 1"
43
+ }
44
+ }