anthropic-gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -0
- package/README.md +75 -0
- package/cli.js +261 -0
- package/config.example.json +20 -0
- package/lib/server.js +132 -0
- package/package.json +39 -0
- package/vendor/LICENSE.claude-adapter +21 -0
- package/vendor/dist/cli.js +288 -0
- package/vendor/dist/converters/index.js +22 -0
- package/vendor/dist/converters/request.js +349 -0
- package/vendor/dist/converters/response.js +125 -0
- package/vendor/dist/converters/streaming.js +308 -0
- package/vendor/dist/converters/tools.js +51 -0
- package/vendor/dist/converters/xmlPrompt.js +87 -0
- package/vendor/dist/converters/xmlStreaming.js +258 -0
- package/vendor/dist/index.js +32 -0
- package/vendor/dist/server/handlers.js +184 -0
- package/vendor/dist/server/index.js +116 -0
- package/vendor/dist/types/anthropic.js +4 -0
- package/vendor/dist/types/config.js +4 -0
- package/vendor/dist/types/index.js +21 -0
- package/vendor/dist/types/openai.js +4 -0
- package/vendor/dist/utils/config.js +169 -0
- package/vendor/dist/utils/errorLog.js +61 -0
- package/vendor/dist/utils/fileStorage.js +114 -0
- package/vendor/dist/utils/index.js +19 -0
- package/vendor/dist/utils/logger.js +138 -0
- package/vendor/dist/utils/metadata.js +128 -0
- package/vendor/dist/utils/provider.js +14 -0
- package/vendor/dist/utils/tokenUsage.js +32 -0
- package/vendor/dist/utils/ui.js +107 -0
- package/vendor/dist/utils/update.js +112 -0
- package/vendor/dist/utils/validation.js +130 -0
- package/vendor/package.json +6 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
exports.saveConfig = saveConfig;
|
|
38
|
+
exports.ensureProxyAuthToken = ensureProxyAuthToken;
|
|
39
|
+
exports.preserveProxyAuthToken = preserveProxyAuthToken;
|
|
40
|
+
exports.configExists = configExists;
|
|
41
|
+
exports.getConfigDir = getConfigDir;
|
|
42
|
+
exports.updateClaudeJson = updateClaudeJson;
|
|
43
|
+
exports.updateClaudeSettings = updateClaudeSettings;
|
|
44
|
+
exports.getClaudePaths = getClaudePaths;
|
|
45
|
+
// Configuration file management utilities
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const os = __importStar(require("os"));
|
|
49
|
+
const crypto_1 = require("crypto");
|
|
50
|
+
const fileStorage_1 = require("./fileStorage");
|
|
51
|
+
const CONFIG_DIR = path.join(os.homedir(), '.claude-adapter');
|
|
52
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
53
|
+
/**
|
|
54
|
+
* Load configuration from ~/.claude-adapter/config.json
|
|
55
|
+
*/
|
|
56
|
+
function loadConfig() {
|
|
57
|
+
try {
|
|
58
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
(0, fileStorage_1.ensureDirExists)(CONFIG_DIR);
|
|
62
|
+
(0, fileStorage_1.hardenPrivateFile)(CONFIG_FILE);
|
|
63
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
64
|
+
return JSON.parse(content);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Save configuration to ~/.claude-adapter/config.json
|
|
72
|
+
*/
|
|
73
|
+
function saveConfig(config) {
|
|
74
|
+
(0, fileStorage_1.ensureDirExists)(CONFIG_DIR);
|
|
75
|
+
(0, fileStorage_1.writePrivateJsonFile)(CONFIG_FILE, config);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Add the proxy credential required by current versions to a legacy config.
|
|
79
|
+
* The value is generated once and then preserved through reconfiguration.
|
|
80
|
+
*/
|
|
81
|
+
function ensureProxyAuthToken(config) {
|
|
82
|
+
if (typeof config.proxyAuthToken === 'string' && config.proxyAuthToken.trim().length > 0) {
|
|
83
|
+
return config;
|
|
84
|
+
}
|
|
85
|
+
const migratedConfig = {
|
|
86
|
+
...config,
|
|
87
|
+
proxyAuthToken: (0, crypto_1.randomBytes)(32).toString('base64url'),
|
|
88
|
+
};
|
|
89
|
+
saveConfig(migratedConfig);
|
|
90
|
+
return migratedConfig;
|
|
91
|
+
}
|
|
92
|
+
/** Preserve the existing proxy token when the provider configuration changes. */
|
|
93
|
+
function preserveProxyAuthToken(nextConfig, previousConfig) {
|
|
94
|
+
return previousConfig?.proxyAuthToken
|
|
95
|
+
? { ...nextConfig, proxyAuthToken: previousConfig.proxyAuthToken }
|
|
96
|
+
: nextConfig;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if configuration exists
|
|
100
|
+
*/
|
|
101
|
+
function configExists() {
|
|
102
|
+
return fs.existsSync(CONFIG_FILE);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the config directory path
|
|
106
|
+
*/
|
|
107
|
+
function getConfigDir() {
|
|
108
|
+
return CONFIG_DIR;
|
|
109
|
+
}
|
|
110
|
+
// Claude settings file paths
|
|
111
|
+
const CLAUDE_JSON_PATH = path.join(os.homedir(), '.claude.json');
|
|
112
|
+
const CLAUDE_SETTINGS_DIR = path.join(os.homedir(), '.claude');
|
|
113
|
+
const CLAUDE_SETTINGS_PATH = path.join(CLAUDE_SETTINGS_DIR, 'settings.json');
|
|
114
|
+
/**
|
|
115
|
+
* Update ~/.claude.json to set hasCompletedOnboarding
|
|
116
|
+
*/
|
|
117
|
+
function updateClaudeJson() {
|
|
118
|
+
let claudeJson = {};
|
|
119
|
+
try {
|
|
120
|
+
if (fs.existsSync(CLAUDE_JSON_PATH)) {
|
|
121
|
+
const content = fs.readFileSync(CLAUDE_JSON_PATH, 'utf-8');
|
|
122
|
+
claudeJson = JSON.parse(content);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Start fresh if file is corrupted
|
|
127
|
+
claudeJson = {};
|
|
128
|
+
}
|
|
129
|
+
claudeJson.hasCompletedOnboarding = true;
|
|
130
|
+
// Do not change permissions on the user's entire home directory.
|
|
131
|
+
(0, fileStorage_1.writePrivateJsonFile)(CLAUDE_JSON_PATH, claudeJson, false);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Update ~/.claude/settings.json with proxy environment variables
|
|
135
|
+
*/
|
|
136
|
+
function updateClaudeSettings(proxyUrl, models, proxyAuthToken) {
|
|
137
|
+
(0, fileStorage_1.ensureDirExists)(CLAUDE_SETTINGS_DIR);
|
|
138
|
+
let settings = {};
|
|
139
|
+
try {
|
|
140
|
+
if (fs.existsSync(CLAUDE_SETTINGS_PATH)) {
|
|
141
|
+
const content = fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8');
|
|
142
|
+
settings = JSON.parse(content);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Start fresh if file is corrupted
|
|
147
|
+
settings = {};
|
|
148
|
+
}
|
|
149
|
+
// Merge env settings
|
|
150
|
+
settings.env = {
|
|
151
|
+
...(settings.env || {}),
|
|
152
|
+
ANTHROPIC_BASE_URL: proxyUrl,
|
|
153
|
+
ANTHROPIC_AUTH_TOKEN: proxyAuthToken,
|
|
154
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: models.opus,
|
|
155
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: models.sonnet,
|
|
156
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: models.haiku,
|
|
157
|
+
};
|
|
158
|
+
(0, fileStorage_1.writePrivateJsonFile)(CLAUDE_SETTINGS_PATH, settings);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get paths for display purposes
|
|
162
|
+
*/
|
|
163
|
+
function getClaudePaths() {
|
|
164
|
+
return {
|
|
165
|
+
claudeJson: CLAUDE_JSON_PATH,
|
|
166
|
+
claudeSettings: CLAUDE_SETTINGS_PATH,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordError = recordError;
|
|
4
|
+
// Error logging utility
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const fileStorage_1 = require("./fileStorage");
|
|
7
|
+
const ERROR_DIR = (0, path_1.join)((0, fileStorage_1.getBaseDir)(), 'error_logs');
|
|
8
|
+
/**
|
|
9
|
+
* Get the file path for a given date
|
|
10
|
+
*/
|
|
11
|
+
function getErrorFilePath(dateStr) {
|
|
12
|
+
return (0, path_1.join)(ERROR_DIR, `${dateStr}.jsonl`);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract error details from various error types
|
|
16
|
+
*/
|
|
17
|
+
function extractErrorDetails(error) {
|
|
18
|
+
const details = {
|
|
19
|
+
message: error.message,
|
|
20
|
+
};
|
|
21
|
+
// Extract OpenAI SDK error properties
|
|
22
|
+
if ('status' in error) {
|
|
23
|
+
details.status = error.status;
|
|
24
|
+
}
|
|
25
|
+
if ('code' in error) {
|
|
26
|
+
details.code = error.code;
|
|
27
|
+
}
|
|
28
|
+
if ('type' in error) {
|
|
29
|
+
details.type = error.type;
|
|
30
|
+
}
|
|
31
|
+
return details;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Error codes that should not be logged (user errors, not API issues)
|
|
35
|
+
*/
|
|
36
|
+
const SKIP_ERROR_CODES = [401, 402, 404, 429];
|
|
37
|
+
/**
|
|
38
|
+
* Record error to the daily file
|
|
39
|
+
* Non-blocking, fails silently on errors
|
|
40
|
+
* Skips common user errors like auth failures and rate limits
|
|
41
|
+
*/
|
|
42
|
+
function recordError(error, context) {
|
|
43
|
+
try {
|
|
44
|
+
// Skip logging for common user-related errors
|
|
45
|
+
if ('status' in error && SKIP_ERROR_CODES.includes(error.status)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
(0, fileStorage_1.ensureDirExists)(ERROR_DIR);
|
|
49
|
+
const record = {
|
|
50
|
+
timestamp: new Date().toISOString(),
|
|
51
|
+
...context,
|
|
52
|
+
error: extractErrorDetails(error),
|
|
53
|
+
};
|
|
54
|
+
const filePath = getErrorFilePath((0, fileStorage_1.getTodayDateString)());
|
|
55
|
+
(0, fileStorage_1.appendJsonLine)(filePath, record);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Fail silently - don't interrupt API flow for error logging
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=errorLog.js.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTodayDateString = getTodayDateString;
|
|
4
|
+
exports.ensureDirExists = ensureDirExists;
|
|
5
|
+
exports.getBaseDir = getBaseDir;
|
|
6
|
+
exports.repairPrivateStoragePermissions = repairPrivateStoragePermissions;
|
|
7
|
+
exports.hardenPrivateFile = hardenPrivateFile;
|
|
8
|
+
exports.appendJsonLine = appendJsonLine;
|
|
9
|
+
exports.writePrivateJsonFile = writePrivateJsonFile;
|
|
10
|
+
// Shared file storage utilities for daily JSON files
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
const os_1 = require("os");
|
|
14
|
+
const path_1 = require("path");
|
|
15
|
+
// Base directory for all claude-adapter data
|
|
16
|
+
const BASE_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude-adapter');
|
|
17
|
+
/**
|
|
18
|
+
* Get today's date as YYYY-MM-DD
|
|
19
|
+
*/
|
|
20
|
+
function getTodayDateString() {
|
|
21
|
+
return new Date().toISOString().split('T')[0];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ensure a directory exists, creating it if necessary
|
|
25
|
+
*/
|
|
26
|
+
function ensureDirExists(dirPath) {
|
|
27
|
+
if (!(0, fs_1.existsSync)(dirPath)) {
|
|
28
|
+
(0, fs_1.mkdirSync)(dirPath, { recursive: true, mode: 0o700 });
|
|
29
|
+
}
|
|
30
|
+
// Windows relies on the current user's profile ACL. POSIX modes protect
|
|
31
|
+
// configuration, metadata, usage, and error logs from other local users.
|
|
32
|
+
if (process.platform !== 'win32') {
|
|
33
|
+
(0, fs_1.chmodSync)(dirPath, 0o700);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the base storage directory
|
|
38
|
+
*/
|
|
39
|
+
function getBaseDir() {
|
|
40
|
+
return BASE_DIR;
|
|
41
|
+
}
|
|
42
|
+
/** Repair all existing adapter-owned storage permissions during startup. */
|
|
43
|
+
function repairPrivateStoragePermissions(baseDir = BASE_DIR) {
|
|
44
|
+
if (process.platform === 'win32') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
ensureDirExists(baseDir);
|
|
48
|
+
for (const entry of (0, fs_1.readdirSync)(baseDir, { withFileTypes: true })) {
|
|
49
|
+
const entryPath = (0, path_1.join)(baseDir, entry.name);
|
|
50
|
+
const stats = (0, fs_1.lstatSync)(entryPath);
|
|
51
|
+
// Never follow symlinks from the private storage tree.
|
|
52
|
+
if (stats.isSymbolicLink()) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (stats.isDirectory()) {
|
|
56
|
+
repairPrivateStoragePermissions(entryPath);
|
|
57
|
+
}
|
|
58
|
+
else if (stats.isFile()) {
|
|
59
|
+
(0, fs_1.chmodSync)(entryPath, 0o600);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Repair permissions on an existing private file. */
|
|
64
|
+
function hardenPrivateFile(filePath) {
|
|
65
|
+
if (process.platform !== 'win32' && (0, fs_1.existsSync)(filePath)) {
|
|
66
|
+
(0, fs_1.chmodSync)(filePath, 0o600);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Append a JSON record to a file (one JSON object per line)
|
|
71
|
+
* This is atomic on most filesystems and avoids race conditions
|
|
72
|
+
*/
|
|
73
|
+
function appendJsonLine(filePath, record) {
|
|
74
|
+
ensureDirExists((0, path_1.dirname)(filePath));
|
|
75
|
+
const line = JSON.stringify(record) + '\n';
|
|
76
|
+
(0, fs_1.appendFileSync)(filePath, line, { encoding: 'utf-8', mode: 0o600 });
|
|
77
|
+
hardenPrivateFile(filePath);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Atomically replace a JSON file with a private file in the same directory.
|
|
81
|
+
* Keeping the temporary file adjacent to the destination makes rename atomic
|
|
82
|
+
* on the filesystems supported by this CLI.
|
|
83
|
+
*/
|
|
84
|
+
function writePrivateJsonFile(filePath, data, secureParentDirectory = true) {
|
|
85
|
+
const parentDirectory = (0, path_1.dirname)(filePath);
|
|
86
|
+
if (secureParentDirectory) {
|
|
87
|
+
ensureDirExists(parentDirectory);
|
|
88
|
+
}
|
|
89
|
+
else if (!(0, fs_1.existsSync)(parentDirectory)) {
|
|
90
|
+
(0, fs_1.mkdirSync)(parentDirectory, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
const tempPath = `${filePath}.${process.pid}.${(0, crypto_1.randomBytes)(8).toString('hex')}.tmp`;
|
|
93
|
+
let descriptor;
|
|
94
|
+
try {
|
|
95
|
+
descriptor = (0, fs_1.openSync)(tempPath, 'w', 0o600);
|
|
96
|
+
(0, fs_1.writeFileSync)(descriptor, JSON.stringify(data, null, 2), 'utf-8');
|
|
97
|
+
(0, fs_1.closeSync)(descriptor);
|
|
98
|
+
descriptor = undefined;
|
|
99
|
+
if (process.platform !== 'win32') {
|
|
100
|
+
(0, fs_1.chmodSync)(tempPath, 0o600);
|
|
101
|
+
}
|
|
102
|
+
(0, fs_1.renameSync)(tempPath, filePath);
|
|
103
|
+
hardenPrivateFile(filePath);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
if (descriptor !== undefined) {
|
|
107
|
+
(0, fs_1.closeSync)(descriptor);
|
|
108
|
+
}
|
|
109
|
+
if ((0, fs_1.existsSync)(tempPath)) {
|
|
110
|
+
(0, fs_1.unlinkSync)(tempPath);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=fileStorage.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Utility exports
|
|
18
|
+
__exportStar(require("./config"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestLogger = exports.Logger = exports.logger = exports.LogLevel = void 0;
|
|
4
|
+
// Structured logger with levels and timestamps
|
|
5
|
+
var LogLevel;
|
|
6
|
+
(function (LogLevel) {
|
|
7
|
+
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
|
8
|
+
LogLevel[LogLevel["INFO"] = 1] = "INFO";
|
|
9
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
|
10
|
+
LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
|
|
11
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
12
|
+
const levelNames = {
|
|
13
|
+
[LogLevel.DEBUG]: 'DEBUG',
|
|
14
|
+
[LogLevel.INFO]: 'INFO',
|
|
15
|
+
[LogLevel.WARN]: 'WARN',
|
|
16
|
+
[LogLevel.ERROR]: 'ERROR',
|
|
17
|
+
};
|
|
18
|
+
const levelColors = {
|
|
19
|
+
[LogLevel.DEBUG]: '\x1b[90m', // gray
|
|
20
|
+
[LogLevel.INFO]: '\x1b[36m', // cyan
|
|
21
|
+
[LogLevel.WARN]: '\x1b[33m', // yellow
|
|
22
|
+
[LogLevel.ERROR]: '\x1b[31m', // red
|
|
23
|
+
};
|
|
24
|
+
const RESET = '\x1b[0m';
|
|
25
|
+
class Logger {
|
|
26
|
+
level;
|
|
27
|
+
prefix;
|
|
28
|
+
constructor(prefix = 'adapter') {
|
|
29
|
+
this.prefix = prefix;
|
|
30
|
+
// Default to INFO, can be overridden by LOG_LEVEL env var
|
|
31
|
+
const envLevel = process.env.LOG_LEVEL?.toUpperCase();
|
|
32
|
+
this.level = this.parseLevel(envLevel) ?? LogLevel.INFO;
|
|
33
|
+
}
|
|
34
|
+
parseLevel(level) {
|
|
35
|
+
switch (level) {
|
|
36
|
+
case 'DEBUG':
|
|
37
|
+
return LogLevel.DEBUG;
|
|
38
|
+
case 'INFO':
|
|
39
|
+
return LogLevel.INFO;
|
|
40
|
+
case 'WARN':
|
|
41
|
+
return LogLevel.WARN;
|
|
42
|
+
case 'ERROR':
|
|
43
|
+
return LogLevel.ERROR;
|
|
44
|
+
default:
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
formatTimestamp() {
|
|
49
|
+
return new Date().toISOString();
|
|
50
|
+
}
|
|
51
|
+
log(level, message, meta) {
|
|
52
|
+
if (level < this.level)
|
|
53
|
+
return;
|
|
54
|
+
let output;
|
|
55
|
+
const color = levelColors[level];
|
|
56
|
+
// Use simple format for INFO in non-debug mode
|
|
57
|
+
if (level === LogLevel.INFO && this.level > LogLevel.DEBUG) {
|
|
58
|
+
output = `${color}${message}${RESET}`;
|
|
59
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
60
|
+
output += ` ${color}${JSON.stringify(meta)}${RESET}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Full format with timestamp for DEBUG or when in debug mode
|
|
65
|
+
const levelName = levelNames[level].padEnd(5);
|
|
66
|
+
const timestamp = this.formatTimestamp();
|
|
67
|
+
output = `${color}[${timestamp}] [${this.prefix}] ${levelName}${RESET} ${message}`;
|
|
68
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
69
|
+
output += ` ${JSON.stringify(meta)}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (level === LogLevel.ERROR) {
|
|
73
|
+
console.error(output);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(output);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
debug(message, meta) {
|
|
80
|
+
this.log(LogLevel.DEBUG, message, meta);
|
|
81
|
+
}
|
|
82
|
+
info(message, meta) {
|
|
83
|
+
this.log(LogLevel.INFO, message, meta);
|
|
84
|
+
}
|
|
85
|
+
warn(message, meta) {
|
|
86
|
+
this.log(LogLevel.WARN, message, meta);
|
|
87
|
+
}
|
|
88
|
+
error(message, error, meta) {
|
|
89
|
+
const errorMeta = error ? { error: error.message, ...meta } : meta;
|
|
90
|
+
this.log(LogLevel.ERROR, message, errorMeta);
|
|
91
|
+
}
|
|
92
|
+
print(message) {
|
|
93
|
+
console.log(message);
|
|
94
|
+
}
|
|
95
|
+
setLevel(level) {
|
|
96
|
+
this.level = level;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a child logger with request context
|
|
100
|
+
*/
|
|
101
|
+
withRequestId(requestId) {
|
|
102
|
+
return new RequestLogger(this, requestId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.Logger = Logger;
|
|
106
|
+
/**
|
|
107
|
+
* Logger bound to a specific request ID for tracing
|
|
108
|
+
*/
|
|
109
|
+
class RequestLogger {
|
|
110
|
+
parent;
|
|
111
|
+
requestId;
|
|
112
|
+
constructor(parent, requestId) {
|
|
113
|
+
this.parent = parent;
|
|
114
|
+
this.requestId = requestId;
|
|
115
|
+
}
|
|
116
|
+
addContext(meta) {
|
|
117
|
+
return { requestId: this.requestId, ...meta };
|
|
118
|
+
}
|
|
119
|
+
debug(message, meta) {
|
|
120
|
+
this.parent.debug(message, this.addContext(meta));
|
|
121
|
+
}
|
|
122
|
+
info(message, meta) {
|
|
123
|
+
this.parent.info(message, this.addContext(meta));
|
|
124
|
+
}
|
|
125
|
+
warn(message, meta) {
|
|
126
|
+
this.parent.warn(message, this.addContext(meta));
|
|
127
|
+
}
|
|
128
|
+
error(message, error, meta) {
|
|
129
|
+
this.parent.error(message, error, this.addContext(meta));
|
|
130
|
+
}
|
|
131
|
+
print(message) {
|
|
132
|
+
this.parent.print(message);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.RequestLogger = RequestLogger;
|
|
136
|
+
// Export singleton instance
|
|
137
|
+
exports.logger = new Logger();
|
|
138
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMetadata = getMetadata;
|
|
4
|
+
exports.updateLatestVersion = updateLatestVersion;
|
|
5
|
+
exports.getCachedLatestVersion = getCachedLatestVersion;
|
|
6
|
+
// Metadata storage utility
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const os_1 = require("os");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const crypto_1 = require("crypto");
|
|
11
|
+
const package_json_1 = require("../../package.json");
|
|
12
|
+
const fileStorage_1 = require("./fileStorage");
|
|
13
|
+
const METADATA_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude-adapter');
|
|
14
|
+
const METADATA_FILE = (0, path_1.join)(METADATA_DIR, 'metadata.json');
|
|
15
|
+
/**
|
|
16
|
+
* Generate a unique user ID
|
|
17
|
+
*/
|
|
18
|
+
function generateUserId() {
|
|
19
|
+
return (0, crypto_1.randomBytes)(16).toString('hex');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get OS name
|
|
23
|
+
*/
|
|
24
|
+
function getOsName() {
|
|
25
|
+
return (0, os_1.platform)();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Ensure metadata directory exists
|
|
29
|
+
*/
|
|
30
|
+
function ensureMetadataDir() {
|
|
31
|
+
(0, fileStorage_1.ensureDirExists)(METADATA_DIR);
|
|
32
|
+
}
|
|
33
|
+
let cachedMetadata = null;
|
|
34
|
+
/**
|
|
35
|
+
* Load metadata from file
|
|
36
|
+
*/
|
|
37
|
+
function loadMetadata() {
|
|
38
|
+
if (cachedMetadata) {
|
|
39
|
+
return cachedMetadata;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
if ((0, fs_1.existsSync)(METADATA_FILE)) {
|
|
43
|
+
ensureMetadataDir();
|
|
44
|
+
(0, fileStorage_1.hardenPrivateFile)(METADATA_FILE);
|
|
45
|
+
const data = (0, fs_1.readFileSync)(METADATA_FILE, 'utf-8');
|
|
46
|
+
cachedMetadata = JSON.parse(data);
|
|
47
|
+
return cachedMetadata;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore read errors
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Save metadata to file
|
|
57
|
+
*/
|
|
58
|
+
function saveMetadata(metadata) {
|
|
59
|
+
try {
|
|
60
|
+
ensureMetadataDir();
|
|
61
|
+
(0, fileStorage_1.writePrivateJsonFile)(METADATA_FILE, metadata);
|
|
62
|
+
cachedMetadata = metadata;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Ignore write errors
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get or create metadata
|
|
70
|
+
* Creates new metadata on first run, updates currentVersion on subsequent runs
|
|
71
|
+
*/
|
|
72
|
+
function getMetadata() {
|
|
73
|
+
let metadata = loadMetadata();
|
|
74
|
+
if (!metadata) {
|
|
75
|
+
// First run - create new metadata
|
|
76
|
+
metadata = {
|
|
77
|
+
userId: generateUserId(),
|
|
78
|
+
platform: getOsName(),
|
|
79
|
+
platformRelease: (0, os_1.release)(),
|
|
80
|
+
currentVersion: package_json_1.version,
|
|
81
|
+
createdAt: new Date().toISOString(),
|
|
82
|
+
};
|
|
83
|
+
saveMetadata(metadata);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Update current version if changed
|
|
87
|
+
if (metadata.currentVersion !== package_json_1.version) {
|
|
88
|
+
metadata.currentVersion = package_json_1.version;
|
|
89
|
+
saveMetadata(metadata);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return metadata;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Update latest version in metadata (called after npm registry check)
|
|
96
|
+
*/
|
|
97
|
+
function updateLatestVersion(version) {
|
|
98
|
+
try {
|
|
99
|
+
const metadata = loadMetadata();
|
|
100
|
+
if (metadata) {
|
|
101
|
+
metadata.latestVersion = version;
|
|
102
|
+
metadata.latestVersionTimestamp = Date.now();
|
|
103
|
+
saveMetadata(metadata);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Ignore errors
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get cached latest version info
|
|
112
|
+
*/
|
|
113
|
+
function getCachedLatestVersion() {
|
|
114
|
+
try {
|
|
115
|
+
const metadata = loadMetadata();
|
|
116
|
+
if (metadata?.latestVersion && metadata?.latestVersionTimestamp) {
|
|
117
|
+
return {
|
|
118
|
+
version: metadata.latestVersion,
|
|
119
|
+
timestamp: metadata.latestVersionTimestamp,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore errors
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isAzureOpenAIEndpoint = isAzureOpenAIEndpoint;
|
|
4
|
+
function isAzureOpenAIEndpoint(baseUrl) {
|
|
5
|
+
try {
|
|
6
|
+
const url = new URL(baseUrl);
|
|
7
|
+
const hostname = url.hostname.toLowerCase();
|
|
8
|
+
return hostname.endsWith('.openai.azure.com') || hostname.includes('.services.ai.azure.com');
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordUsage = recordUsage;
|
|
4
|
+
// Token usage storage utility
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const fileStorage_1 = require("./fileStorage");
|
|
7
|
+
const USAGE_DIR = (0, path_1.join)((0, fileStorage_1.getBaseDir)(), 'token_usage');
|
|
8
|
+
/**
|
|
9
|
+
* Get the file path for a given date
|
|
10
|
+
*/
|
|
11
|
+
function getUsageFilePath(dateStr) {
|
|
12
|
+
return (0, path_1.join)(USAGE_DIR, `${dateStr}.jsonl`);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Record token usage to the daily file
|
|
16
|
+
* Non-blocking, fails silently on errors
|
|
17
|
+
*/
|
|
18
|
+
function recordUsage(data) {
|
|
19
|
+
try {
|
|
20
|
+
(0, fileStorage_1.ensureDirExists)(USAGE_DIR);
|
|
21
|
+
const record = {
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
...data
|
|
24
|
+
};
|
|
25
|
+
const filePath = getUsageFilePath((0, fileStorage_1.getTodayDateString)());
|
|
26
|
+
(0, fileStorage_1.appendJsonLine)(filePath, record);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Fail silently - don't interrupt API flow for usage tracking
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=tokenUsage.js.map
|