@rynfar/meridian 1.27.6 → 1.28.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 +78 -0
- package/dist/cli-340h1chz.js +33 -0
- package/dist/cli-g9ypdz51.js +113 -0
- package/dist/cli-vdp9s10c.js +115 -0
- package/dist/{cli-z8ny8e85.js → cli-zcxn6xmn.js} +186 -34
- package/dist/cli.js +39 -2
- package/dist/profileCli-pdqrpw0m.js +239 -0
- package/dist/profilePage-9nkbct3w.js +275 -0
- package/dist/profiles-ntgacztq.js +26 -0
- package/dist/proxy/models.d.ts +13 -1
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/profiles.d.ts +81 -0
- package/dist/proxy/profiles.d.ts.map +1 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/settings.d.ts +22 -0
- package/dist/proxy/settings.d.ts.map +1 -0
- package/dist/proxy/types.d.ts +5 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/server.js +4 -1
- package/dist/telemetry/dashboard.d.ts +1 -1
- package/dist/telemetry/dashboard.d.ts.map +1 -1
- package/dist/telemetry/landing.d.ts +1 -1
- package/dist/telemetry/landing.d.ts.map +1 -1
- package/dist/telemetry/profileBar.d.ts +11 -0
- package/dist/telemetry/profileBar.d.ts.map +1 -0
- package/dist/telemetry/profilePage.d.ts +6 -0
- package/dist/telemetry/profilePage.d.ts.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setSetting
|
|
3
|
+
} from "./cli-340h1chz.js";
|
|
4
|
+
import"./cli-a05ws7rb.js";
|
|
5
|
+
|
|
6
|
+
// src/proxy/profileCli.ts
|
|
7
|
+
import { mkdirSync, existsSync, rmSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
var PROFILES_DIR = join(homedir(), ".config", "meridian", "profiles");
|
|
12
|
+
var CONFIG_FILE = join(homedir(), ".config", "meridian", "profiles.json");
|
|
13
|
+
function ensureProfilesDir() {
|
|
14
|
+
mkdirSync(PROFILES_DIR, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
function getProfileDir(id) {
|
|
17
|
+
return join(PROFILES_DIR, id);
|
|
18
|
+
}
|
|
19
|
+
function loadProfileConfig() {
|
|
20
|
+
if (!existsSync(CONFIG_FILE))
|
|
21
|
+
return [];
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.warn(`[meridian] Failed to read ${CONFIG_FILE}: ${err instanceof Error ? err.message : err}`);
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function saveProfileConfig(profiles) {
|
|
30
|
+
ensureProfilesDir();
|
|
31
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(profiles, null, 2) + `
|
|
32
|
+
`, { mode: 384 });
|
|
33
|
+
}
|
|
34
|
+
function getAuthStatus(configDir) {
|
|
35
|
+
try {
|
|
36
|
+
const result = execSync("claude auth status", {
|
|
37
|
+
timeout: 5000,
|
|
38
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: configDir },
|
|
39
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
40
|
+
});
|
|
41
|
+
return JSON.parse(result.toString());
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.warn(`[meridian] Auth check failed for ${configDir}: ${err instanceof Error ? err.message : err}`);
|
|
44
|
+
return { loggedIn: false };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function profileAdd(id) {
|
|
48
|
+
if (!id || /[^a-zA-Z0-9_-]/.test(id)) {
|
|
49
|
+
console.error("\x1B[31m✗ Invalid profile ID.\x1B[0m Use only letters, numbers, hyphens, underscores.");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const profiles = loadProfileConfig();
|
|
53
|
+
if (profiles.find((p) => p.id === id)) {
|
|
54
|
+
console.error(`\x1B[31m✗ Profile "${id}" already exists.\x1B[0m`);
|
|
55
|
+
console.error(` Run: meridian profile list`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const defaultClaudeDir = join(homedir(), ".claude");
|
|
59
|
+
const alreadyImported = profiles.some((p) => p.claudeConfigDir === defaultClaudeDir);
|
|
60
|
+
if (!alreadyImported) {
|
|
61
|
+
const defaultAuth = getAuthStatus(defaultClaudeDir);
|
|
62
|
+
if (defaultAuth.loggedIn) {
|
|
63
|
+
console.log(`\x1B[32m✓ Found existing Claude credentials (${defaultAuth.email}, ${defaultAuth.subscriptionType || "unknown"})\x1B[0m`);
|
|
64
|
+
const answer = promptYesNo(` Import as profile "${id}"?`);
|
|
65
|
+
if (answer) {
|
|
66
|
+
profiles.push({ id, claudeConfigDir: defaultClaudeDir });
|
|
67
|
+
saveProfileConfig(profiles);
|
|
68
|
+
console.log(`\x1B[32m✓ Profile "${id}" imported — using ${defaultAuth.email}\x1B[0m`);
|
|
69
|
+
printEnvHint(profiles);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(" Skipped import — will create a fresh profile instead.");
|
|
74
|
+
console.log();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const configDir = getProfileDir(id);
|
|
78
|
+
mkdirSync(configDir, { recursive: true });
|
|
79
|
+
console.log(`\x1B[36mAdding profile: ${id}\x1B[0m`);
|
|
80
|
+
console.log(` Config dir: ${configDir}`);
|
|
81
|
+
console.log();
|
|
82
|
+
const existingAuth = getAuthStatus(configDir);
|
|
83
|
+
if (existingAuth.loggedIn) {
|
|
84
|
+
console.log(`\x1B[32m✓ Already authenticated as ${existingAuth.email}\x1B[0m`);
|
|
85
|
+
profiles.push({ id, claudeConfigDir: configDir });
|
|
86
|
+
saveProfileConfig(profiles);
|
|
87
|
+
printEnvHint(profiles);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
console.log("\x1B[33m⚠ Important: Before logging in, make sure you're signed into the");
|
|
91
|
+
console.log(` correct Claude account in your browser (the one for "${id}").\x1B[0m`);
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(" If you're currently signed into a different account:");
|
|
94
|
+
console.log(" 1. Go to https://claude.ai and sign out");
|
|
95
|
+
console.log(" 2. Sign in with the account you want for this profile");
|
|
96
|
+
console.log(" 3. Come back here — the login will open your browser");
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(" Press Ctrl+C to cancel, or wait for the browser to open...");
|
|
99
|
+
console.log();
|
|
100
|
+
const result = spawnSync("claude", ["auth", "login"], {
|
|
101
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: configDir },
|
|
102
|
+
stdio: "inherit"
|
|
103
|
+
});
|
|
104
|
+
if (result.status !== 0) {
|
|
105
|
+
console.error("\x1B[31m✗ Login failed.\x1B[0m");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const auth = getAuthStatus(configDir);
|
|
109
|
+
if (!auth.loggedIn) {
|
|
110
|
+
console.error("\x1B[31m✗ Login did not complete. Try again: meridian profile add " + id + "\x1B[0m");
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
console.log();
|
|
114
|
+
console.log(`\x1B[32m✓ Profile "${id}" created — logged in as ${auth.email} (${auth.subscriptionType || "unknown"})\x1B[0m`);
|
|
115
|
+
profiles.push({ id, claudeConfigDir: configDir });
|
|
116
|
+
saveProfileConfig(profiles);
|
|
117
|
+
printEnvHint(profiles);
|
|
118
|
+
}
|
|
119
|
+
function profileList() {
|
|
120
|
+
const profiles = loadProfileConfig();
|
|
121
|
+
if (profiles.length === 0) {
|
|
122
|
+
console.log("No profiles configured.");
|
|
123
|
+
console.log(" Add one: meridian profile add <name>");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
console.log(`Profiles:
|
|
127
|
+
`);
|
|
128
|
+
for (const p of profiles) {
|
|
129
|
+
const auth = getAuthStatus(p.claudeConfigDir ?? "");
|
|
130
|
+
const status = auth.loggedIn ? `\x1B[32m✓ ${auth.email} (${auth.subscriptionType || "unknown"})\x1B[0m` : "\x1B[31m✗ not logged in\x1B[0m";
|
|
131
|
+
console.log(` ${p.id.padEnd(20)} ${status}`);
|
|
132
|
+
}
|
|
133
|
+
console.log();
|
|
134
|
+
printEnvHint(profiles);
|
|
135
|
+
}
|
|
136
|
+
function profileRemove(id) {
|
|
137
|
+
const profiles = loadProfileConfig();
|
|
138
|
+
const idx = profiles.findIndex((p) => p.id === id);
|
|
139
|
+
if (idx === -1) {
|
|
140
|
+
console.error(`\x1B[31m✗ Profile "${id}" not found.\x1B[0m`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const configDir = profiles[idx].claudeConfigDir ?? "";
|
|
144
|
+
profiles.splice(idx, 1);
|
|
145
|
+
saveProfileConfig(profiles);
|
|
146
|
+
if (configDir && existsSync(configDir) && configDir.startsWith(PROFILES_DIR)) {
|
|
147
|
+
rmSync(configDir, { recursive: true, force: true });
|
|
148
|
+
}
|
|
149
|
+
console.log(`\x1B[32m✓ Profile "${id}" removed.\x1B[0m`);
|
|
150
|
+
if (profiles.length > 0) {
|
|
151
|
+
printEnvHint(profiles);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function profileSwitch(id) {
|
|
155
|
+
const port = process.env.MERIDIAN_PORT ?? process.env.CLAUDE_PROXY_PORT ?? "3456";
|
|
156
|
+
const host = process.env.MERIDIAN_HOST ?? process.env.CLAUDE_PROXY_HOST ?? "127.0.0.1";
|
|
157
|
+
try {
|
|
158
|
+
const res = await fetch(`http://${host}:${port}/profiles/active`, {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers: { "Content-Type": "application/json" },
|
|
161
|
+
body: JSON.stringify({ profile: id }),
|
|
162
|
+
signal: AbortSignal.timeout(5000)
|
|
163
|
+
});
|
|
164
|
+
const body = await res.json();
|
|
165
|
+
if (body.success) {
|
|
166
|
+
setSetting("activeProfile", id);
|
|
167
|
+
console.log(`\x1B[32m✓ Switched to profile: ${id}\x1B[0m`);
|
|
168
|
+
} else {
|
|
169
|
+
console.error(`\x1B[31m✗ ${body.error}\x1B[0m`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
console.error("\x1B[31m✗ Could not connect to Meridian. Is it running?\x1B[0m");
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function profileLogin(id) {
|
|
178
|
+
const profiles = loadProfileConfig();
|
|
179
|
+
const profile = profiles.find((p) => p.id === id);
|
|
180
|
+
if (!profile) {
|
|
181
|
+
console.error(`\x1B[31m✗ Profile "${id}" not found.\x1B[0m Run: meridian profile add ${id}`);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
console.log(`\x1B[36mRe-authenticating profile: ${id}\x1B[0m`);
|
|
185
|
+
console.log();
|
|
186
|
+
console.log("\x1B[33m⚠ Make sure you're signed into the correct Claude account in your browser.\x1B[0m");
|
|
187
|
+
console.log();
|
|
188
|
+
const result = spawnSync("claude", ["auth", "login"], {
|
|
189
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: profile.claudeConfigDir },
|
|
190
|
+
stdio: "inherit"
|
|
191
|
+
});
|
|
192
|
+
if (result.status !== 0) {
|
|
193
|
+
console.error("\x1B[31m✗ Login failed.\x1B[0m");
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
const auth = getAuthStatus(profile.claudeConfigDir ?? "");
|
|
197
|
+
if (auth.loggedIn) {
|
|
198
|
+
console.log(`\x1B[32m✓ Profile "${id}" authenticated as ${auth.email}\x1B[0m`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function promptYesNo(question) {
|
|
202
|
+
const result = spawnSync("node", ["-e", [
|
|
203
|
+
`process.stdout.write(${JSON.stringify(`${question} [Y/n] `)});`,
|
|
204
|
+
`const rl = require("readline").createInterface({ input: process.stdin });`,
|
|
205
|
+
`rl.once("line", (a) => { process.stdout.write(a); rl.close(); });`,
|
|
206
|
+
`rl.once("close", () => process.exit(0));`
|
|
207
|
+
].join(`
|
|
208
|
+
`)], { stdio: ["inherit", "pipe", "inherit"] });
|
|
209
|
+
const answer = (result.stdout?.toString().trim() ?? "").toLowerCase();
|
|
210
|
+
return answer !== "n" && answer !== "no";
|
|
211
|
+
}
|
|
212
|
+
function printEnvHint(_profiles) {
|
|
213
|
+
console.log(`\x1B[90mConfig: ${CONFIG_FILE}\x1B[0m`);
|
|
214
|
+
console.log("\x1B[90mProfiles are picked up automatically — no restart needed.\x1B[0m");
|
|
215
|
+
}
|
|
216
|
+
function profileHelp() {
|
|
217
|
+
console.log(`meridian profile — manage Claude account profiles
|
|
218
|
+
|
|
219
|
+
Commands:
|
|
220
|
+
meridian profile add <name> Add a profile and authenticate
|
|
221
|
+
meridian profile list List profiles and auth status
|
|
222
|
+
meridian profile remove <name> Remove a profile
|
|
223
|
+
meridian profile switch <name> Switch the active profile (requires running proxy)
|
|
224
|
+
meridian profile login <name> Re-authenticate an existing profile
|
|
225
|
+
|
|
226
|
+
Examples:
|
|
227
|
+
meridian profile add personal # Add personal account
|
|
228
|
+
meridian profile add work # Add work account
|
|
229
|
+
meridian profile switch work # Switch to work account
|
|
230
|
+
meridian profile list # Show all profiles`);
|
|
231
|
+
}
|
|
232
|
+
export {
|
|
233
|
+
profileSwitch,
|
|
234
|
+
profileRemove,
|
|
235
|
+
profileLogin,
|
|
236
|
+
profileList,
|
|
237
|
+
profileHelp,
|
|
238
|
+
profileAdd
|
|
239
|
+
};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import {
|
|
2
|
+
profileBarCss,
|
|
3
|
+
profileBarHtml,
|
|
4
|
+
profileBarJs
|
|
5
|
+
} from "./cli-g9ypdz51.js";
|
|
6
|
+
import"./cli-a05ws7rb.js";
|
|
7
|
+
|
|
8
|
+
// src/telemetry/profilePage.ts
|
|
9
|
+
var profilePageHtml = `<!DOCTYPE html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="utf-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
14
|
+
<title>Meridian — Profiles</title>
|
|
15
|
+
<style>
|
|
16
|
+
:root {
|
|
17
|
+
--bg: #0d1117; --surface: #161b22; --border: #30363d;
|
|
18
|
+
--text: #e6edf3; --muted: #8b949e; --accent: #58a6ff;
|
|
19
|
+
--green: #3fb950; --yellow: #d29922; --red: #f85149;
|
|
20
|
+
--purple: #bc8cff;
|
|
21
|
+
}
|
|
22
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
23
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
24
|
+
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
|
25
|
+
.container { max-width: 800px; margin: 0 auto; padding: 24px; }
|
|
26
|
+
h1 { font-size: 20px; font-weight: 600; margin-bottom: 4px; }
|
|
27
|
+
.subtitle { color: var(--muted); font-size: 13px; margin-bottom: 24px; }
|
|
28
|
+
.section { margin-bottom: 32px; }
|
|
29
|
+
.section-title { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase;
|
|
30
|
+
letter-spacing: 0.5px; margin-bottom: 12px; }
|
|
31
|
+
|
|
32
|
+
.profile-card {
|
|
33
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
34
|
+
padding: 20px; margin-bottom: 12px; transition: border-color 0.2s;
|
|
35
|
+
}
|
|
36
|
+
.profile-card.active { border-color: var(--accent); }
|
|
37
|
+
.profile-card-header { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
|
|
38
|
+
.profile-name { font-size: 16px; font-weight: 600; }
|
|
39
|
+
.profile-badge {
|
|
40
|
+
font-size: 10px; padding: 2px 8px; border-radius: 4px; text-transform: uppercase;
|
|
41
|
+
letter-spacing: 0.5px; font-weight: 500;
|
|
42
|
+
}
|
|
43
|
+
.badge-active { background: rgba(88,166,255,0.15); color: var(--accent); }
|
|
44
|
+
.badge-type { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }
|
|
45
|
+
.profile-details {
|
|
46
|
+
display: grid; grid-template-columns: 120px 1fr; gap: 6px 16px; font-size: 13px;
|
|
47
|
+
}
|
|
48
|
+
.detail-label { color: var(--muted); }
|
|
49
|
+
.detail-value { font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 12px; }
|
|
50
|
+
.status-ok { color: var(--green); }
|
|
51
|
+
.status-err { color: var(--red); }
|
|
52
|
+
.switch-btn {
|
|
53
|
+
margin-top: 12px; padding: 6px 16px; font-size: 12px; font-weight: 500;
|
|
54
|
+
background: var(--bg); color: var(--accent); border: 1px solid var(--accent);
|
|
55
|
+
border-radius: 6px; cursor: pointer; transition: all 0.15s;
|
|
56
|
+
}
|
|
57
|
+
.switch-btn:hover { background: rgba(88,166,255,0.1); }
|
|
58
|
+
.switch-btn:disabled { opacity: 0.4; cursor: default; }
|
|
59
|
+
.switch-btn.current { border-color: var(--border); color: var(--muted); cursor: default; }
|
|
60
|
+
|
|
61
|
+
.empty-state {
|
|
62
|
+
text-align: center; padding: 48px; color: var(--muted);
|
|
63
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
64
|
+
}
|
|
65
|
+
.empty-state h2 { font-size: 16px; margin-bottom: 8px; color: var(--text); }
|
|
66
|
+
|
|
67
|
+
.guide {
|
|
68
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
69
|
+
padding: 20px;
|
|
70
|
+
}
|
|
71
|
+
.guide h3 { font-size: 14px; margin-bottom: 12px; }
|
|
72
|
+
.guide ol { padding-left: 20px; font-size: 13px; }
|
|
73
|
+
.guide li { margin-bottom: 8px; }
|
|
74
|
+
.guide code {
|
|
75
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 12px;
|
|
76
|
+
background: var(--bg); padding: 2px 6px; border-radius: 4px; color: var(--purple);
|
|
77
|
+
}
|
|
78
|
+
.guide .warn {
|
|
79
|
+
margin-top: 12px; padding: 12px 16px; background: rgba(210,153,34,0.1);
|
|
80
|
+
border: 1px solid rgba(210,153,34,0.3); border-radius: 8px; font-size: 12px;
|
|
81
|
+
}
|
|
82
|
+
.guide .warn strong { color: var(--yellow); }
|
|
83
|
+
|
|
84
|
+
.mono { font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 12px; }
|
|
85
|
+
.copy-cmd {
|
|
86
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 12px;
|
|
87
|
+
background: var(--bg); padding: 4px 10px; border-radius: 4px; color: var(--purple);
|
|
88
|
+
cursor: pointer; border: 1px solid var(--border); transition: border-color 0.15s;
|
|
89
|
+
}
|
|
90
|
+
.copy-btn {
|
|
91
|
+
background: var(--bg); color: var(--muted); border: 1px solid var(--border);
|
|
92
|
+
border-radius: 4px; padding: 4px 6px; cursor: pointer; display: inline-flex;
|
|
93
|
+
align-items: center; transition: all 0.15s;
|
|
94
|
+
}
|
|
95
|
+
.copy-btn:hover { border-color: var(--accent); color: var(--accent); }
|
|
96
|
+
.copy-btn.copied { color: var(--green); border-color: var(--green); }
|
|
97
|
+
` + profileBarCss + `
|
|
98
|
+
</style>
|
|
99
|
+
</head>
|
|
100
|
+
<body>
|
|
101
|
+
` + profileBarHtml + `
|
|
102
|
+
<div class="container">
|
|
103
|
+
<h1>Profiles</h1>
|
|
104
|
+
<div class="subtitle">Manage Claude account profiles</div>
|
|
105
|
+
|
|
106
|
+
<div id="content"><div style="color:var(--muted);padding:40px;text-align:center">Loading…</div></div>
|
|
107
|
+
|
|
108
|
+
<div class="section" style="margin-top:32px">
|
|
109
|
+
<div class="section-title">Setup Guide</div>
|
|
110
|
+
<div class="guide">
|
|
111
|
+
<h3>How profiles work</h3>
|
|
112
|
+
<p style="font-size:13px;color:var(--muted);margin-bottom:12px">
|
|
113
|
+
Each profile is a separate Claude account with its own login credentials.
|
|
114
|
+
Meridian stores them in isolated config directories and switches between them instantly.
|
|
115
|
+
</p>
|
|
116
|
+
|
|
117
|
+
<h3 style="margin-top:16px">Adding a new profile</h3>
|
|
118
|
+
<ol>
|
|
119
|
+
<li>Open a terminal and run: <code>meridian profile add <name></code></li>
|
|
120
|
+
<li>This opens your browser for Claude login</li>
|
|
121
|
+
<li>Done — the profile is ready to use</li>
|
|
122
|
+
</ol>
|
|
123
|
+
|
|
124
|
+
<div class="warn">
|
|
125
|
+
<strong>⚠ Important for adding a second account:</strong> Before running
|
|
126
|
+
<code>meridian profile add</code> for a different account, sign out of claude.ai
|
|
127
|
+
in your browser first, then sign in with the other account. Claude’s OAuth
|
|
128
|
+
reuses your browser session — if you’re already signed in, the login will
|
|
129
|
+
silently use the same account.
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<h3 style="margin-top:16px">Switching profiles</h3>
|
|
133
|
+
<ol>
|
|
134
|
+
<li><strong>UI:</strong> Use the dropdown at the top of this page</li>
|
|
135
|
+
<li><strong>CLI:</strong> <code>meridian profile switch <name></code></li>
|
|
136
|
+
<li><strong>Per-request:</strong> Send <code>x-meridian-profile: <name></code> header</li>
|
|
137
|
+
</ol>
|
|
138
|
+
|
|
139
|
+
<h3 style="margin-top:16px">Other commands</h3>
|
|
140
|
+
<div style="font-size:13px;margin-top:8px">
|
|
141
|
+
<code>meridian profile list</code> — show all profiles and auth status<br>
|
|
142
|
+
<code>meridian profile login <name></code> — re-authenticate an expired profile<br>
|
|
143
|
+
<code>meridian profile remove <name></code> — remove a profile
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<script>
|
|
150
|
+
async function refresh() {
|
|
151
|
+
try {
|
|
152
|
+
const res = await fetch('/profiles/list');
|
|
153
|
+
const data = await res.json();
|
|
154
|
+
render(data);
|
|
155
|
+
} catch {
|
|
156
|
+
document.getElementById('content').innerHTML = '<div class="empty-state"><h2>Could not load profiles</h2><p>Is Meridian running?</p></div>';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function esc(s) { var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
|
161
|
+
|
|
162
|
+
function render(data) {
|
|
163
|
+
const profiles = data.profiles || [];
|
|
164
|
+
const active = data.activeProfile;
|
|
165
|
+
|
|
166
|
+
if (profiles.length === 0) {
|
|
167
|
+
document.getElementById('content').innerHTML = '<div class="empty-state">'
|
|
168
|
+
+ '<h2>No profiles configured</h2>'
|
|
169
|
+
+ '<p style="margin-top:8px">Add your first profile from the terminal:</p>'
|
|
170
|
+
+ '<p style="margin-top:8px"><code class="mono" style="background:var(--bg);padding:8px 16px;border-radius:6px;display:inline-block">meridian profile add personal</code></p>'
|
|
171
|
+
+ '</div>';
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let html = '<div class="section"><div class="section-title">Configured Profiles</div>';
|
|
176
|
+
|
|
177
|
+
for (const p of profiles) {
|
|
178
|
+
const isActive = p.id === active;
|
|
179
|
+
html += '<div class="profile-card' + (isActive ? ' active' : '') + '">';
|
|
180
|
+
html += '<div class="profile-card-header">';
|
|
181
|
+
html += '<span class="profile-name">' + esc(p.id) + '</span>';
|
|
182
|
+
if (isActive) html += '<span class="profile-badge badge-active">active</span>';
|
|
183
|
+
html += '<span class="profile-badge badge-type">' + esc(p.type || 'claude-max') + '</span>';
|
|
184
|
+
html += '</div>';
|
|
185
|
+
|
|
186
|
+
html += '<div class="profile-details">';
|
|
187
|
+
html += '<span class="detail-label">Status</span>';
|
|
188
|
+
html += '<span class="detail-value ' + (p.loggedIn ? 'status-ok' : 'status-err') + '">'
|
|
189
|
+
+ (p.loggedIn ? '✓ Authenticated' : '✗ Not logged in') + '</span>';
|
|
190
|
+
|
|
191
|
+
if (p.email) {
|
|
192
|
+
html += '<span class="detail-label">Email</span>';
|
|
193
|
+
html += '<span class="detail-value">' + esc(p.email) + '</span>';
|
|
194
|
+
}
|
|
195
|
+
if (p.subscriptionType) {
|
|
196
|
+
html += '<span class="detail-label">Plan</span>';
|
|
197
|
+
html += '<span class="detail-value">' + esc(p.subscriptionType) + '</span>';
|
|
198
|
+
}
|
|
199
|
+
if (p.lastSuccessAt) {
|
|
200
|
+
html += '<span class="detail-label">Last Verified</span>';
|
|
201
|
+
html += '<span class="detail-value" style="color:var(--green)">' + timeAgo(p.lastSuccessAt) + '</span>';
|
|
202
|
+
}
|
|
203
|
+
if (p.lastCheckedAt && (!p.lastSuccessAt || p.lastCheckedAt !== p.lastSuccessAt)) {
|
|
204
|
+
html += '<span class="detail-label">Last Checked</span>';
|
|
205
|
+
html += '<span class="detail-value">' + timeAgo(p.lastCheckedAt) + '</span>';
|
|
206
|
+
}
|
|
207
|
+
html += '</div>';
|
|
208
|
+
|
|
209
|
+
if (!p.loggedIn) {
|
|
210
|
+
html += '<div style="margin-top:12px;padding:10px 14px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.3);border-radius:8px;font-size:12px">';
|
|
211
|
+
html += '<strong style="color:var(--yellow)">⚠ Needs re-authentication</strong>';
|
|
212
|
+
html += '</div>';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
html += '<div style="margin-top:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">';
|
|
216
|
+
html += '<span style="font-size:11px;color:var(--muted)">Login:</span> ';
|
|
217
|
+
html += '<code class="copy-cmd">meridian profile login ' + esc(p.id) + '</code>';
|
|
218
|
+
html += '<button class="copy-btn" data-cmd="meridian profile login ' + esc(p.id) + '" onclick="copyCmd(this)" title="Copy to clipboard">';
|
|
219
|
+
html += '<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25zM5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25z"/></svg>';
|
|
220
|
+
html += '</button>';
|
|
221
|
+
html += '</div>';
|
|
222
|
+
|
|
223
|
+
if (!isActive) {
|
|
224
|
+
html += '<button class="switch-btn" onclick="switchProfile("'+esc(p.id)+'")">Switch to ' + esc(p.id) + '</button>';
|
|
225
|
+
} else {
|
|
226
|
+
html += '<button class="switch-btn current" disabled>Currently active</button>';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
html += '</div>';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
html += '</div>';
|
|
233
|
+
document.getElementById('content').innerHTML = html;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function timeAgo(ts) {
|
|
237
|
+
if (!ts) return '—';
|
|
238
|
+
var s = Math.floor((Date.now() - ts) / 1000);
|
|
239
|
+
if (s < 5) return 'just now';
|
|
240
|
+
if (s < 60) return s + 's ago';
|
|
241
|
+
if (s < 3600) return Math.floor(s/60) + 'm ago';
|
|
242
|
+
if (s < 86400) return Math.floor(s/3600) + 'h ago';
|
|
243
|
+
return new Date(ts).toLocaleString();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function copyCmd(btn) {
|
|
247
|
+
var cmd = btn.getAttribute('data-cmd');
|
|
248
|
+
navigator.clipboard.writeText(cmd);
|
|
249
|
+
btn.classList.add('copied');
|
|
250
|
+
btn.innerHTML = '✓';
|
|
251
|
+
setTimeout(function() {
|
|
252
|
+
btn.classList.remove('copied');
|
|
253
|
+
btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25zM5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25z"/></svg>';
|
|
254
|
+
}, 1500);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function switchProfile(id) {
|
|
258
|
+
const res = await fetch('/profiles/active', {
|
|
259
|
+
method: 'POST',
|
|
260
|
+
headers: { 'Content-Type': 'application/json' },
|
|
261
|
+
body: JSON.stringify({ profile: id })
|
|
262
|
+
});
|
|
263
|
+
const data = await res.json();
|
|
264
|
+
if (data.success) refresh();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
refresh();
|
|
268
|
+
setInterval(refresh, 10000);
|
|
269
|
+
` + profileBarJs + `
|
|
270
|
+
</script>
|
|
271
|
+
</body>
|
|
272
|
+
</html>`;
|
|
273
|
+
export {
|
|
274
|
+
profilePageHtml
|
|
275
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
enableDiskProfileDiscovery,
|
|
3
|
+
getActiveProfileId,
|
|
4
|
+
getEffectiveProfiles,
|
|
5
|
+
hasProfiles,
|
|
6
|
+
listProfiles,
|
|
7
|
+
loadProfilesFromDisk,
|
|
8
|
+
resetActiveProfile,
|
|
9
|
+
resolveProfile,
|
|
10
|
+
restoreActiveProfile,
|
|
11
|
+
setActiveProfile
|
|
12
|
+
} from "./cli-vdp9s10c.js";
|
|
13
|
+
import"./cli-340h1chz.js";
|
|
14
|
+
import"./cli-a05ws7rb.js";
|
|
15
|
+
export {
|
|
16
|
+
setActiveProfile,
|
|
17
|
+
restoreActiveProfile,
|
|
18
|
+
resolveProfile,
|
|
19
|
+
resetActiveProfile,
|
|
20
|
+
loadProfilesFromDisk,
|
|
21
|
+
listProfiles,
|
|
22
|
+
hasProfiles,
|
|
23
|
+
getEffectiveProfiles,
|
|
24
|
+
getActiveProfileId,
|
|
25
|
+
enableDiskProfileDiscovery
|
|
26
|
+
};
|
package/dist/proxy/models.d.ts
CHANGED
|
@@ -33,7 +33,19 @@ export declare function stripExtendedContext(model: ClaudeModel): ClaudeModel;
|
|
|
33
33
|
* Check whether a model is using extended (1M) context.
|
|
34
34
|
*/
|
|
35
35
|
export declare function hasExtendedContext(model: ClaudeModel): boolean;
|
|
36
|
-
|
|
36
|
+
/** Get the last successful auth check timestamp for a profile.
|
|
37
|
+
* @param profileId - Profile ID to look up (uses default cache when omitted) */
|
|
38
|
+
export declare function getAuthCacheInfo(profileId?: string): {
|
|
39
|
+
lastCheckedAt: number;
|
|
40
|
+
lastSuccessAt: number;
|
|
41
|
+
isFailure: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* @param profileId - Profile ID for per-profile cache keying (e.g. "work", "personal").
|
|
45
|
+
* When undefined, uses the default (global) auth context.
|
|
46
|
+
* @param envOverrides - Optional env vars for per-profile auth (e.g. CLAUDE_CONFIG_DIR).
|
|
47
|
+
*/
|
|
48
|
+
export declare function getClaudeAuthStatusAsync(profileId?: string, envOverrides?: Record<string, string>): Promise<ClaudeAuthStatus | null>;
|
|
37
49
|
/**
|
|
38
50
|
* Resolve the Claude executable path asynchronously (non-blocking).
|
|
39
51
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAA;AACjF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA0BD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CA8B7H;AAWD;;;;;;GAMG;AACH,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,IAAI,OAAO,CAG3D;AAED,0EAA0E;AAC1E,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAIpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9D;
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAA;AACjF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA0BD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CA8B7H;AAWD;;;;;;GAMG;AACH,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,IAAI,OAAO,CAG3D;AAED,0EAA0E;AAC1E,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAIpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9D;AAaD;gFACgF;AAChF,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAOzH;AAWD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAuD1I;AAOD;;;;;;;;;;GAUG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,CA4DpE;AAED,2CAA2C;AAC3C,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED,kDAAkD;AAClD,wBAAgB,2BAA2B,IAAI,IAAI,CAOlD;AAED;;6DAE6D;AAC7D,wBAAgB,qBAAqB,IAAI,IAAI,CAO5C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG/D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-profile support.
|
|
3
|
+
*
|
|
4
|
+
* Allows a single Meridian instance to route requests to different Claude
|
|
5
|
+
* accounts. Each profile is a named auth context (a CLAUDE_CONFIG_DIR for
|
|
6
|
+
* Max subscriptions, or an API key for direct API access).
|
|
7
|
+
*
|
|
8
|
+
* Profile selection priority:
|
|
9
|
+
* 1. x-meridian-profile request header (per-request override)
|
|
10
|
+
* 2. Active profile (set via POST /profiles/active or UI)
|
|
11
|
+
* 3. First configured profile (or implicit "default" if none configured)
|
|
12
|
+
*
|
|
13
|
+
* This is a leaf module — no imports from server.ts or session/.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Load profiles from ~/.config/meridian/profiles.json.
|
|
17
|
+
* Cached with a 5s TTL so new profiles are picked up without restart,
|
|
18
|
+
* while avoiding synchronous disk I/O on every request.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadProfilesFromDisk(): ProfileConfig[];
|
|
21
|
+
export type ProfileType = "claude-max" | "api";
|
|
22
|
+
export interface ProfileConfig {
|
|
23
|
+
/** Unique profile identifier (e.g. "personal", "work") */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Auth type — "claude-max" uses CLAUDE_CONFIG_DIR, "api" uses ANTHROPIC_API_KEY */
|
|
26
|
+
type?: ProfileType;
|
|
27
|
+
/** Path to .claude config directory (claude-max profiles) */
|
|
28
|
+
claudeConfigDir?: string;
|
|
29
|
+
/** Anthropic API key (api profiles) */
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
/** Anthropic base URL override (api profiles) */
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ResolvedProfile {
|
|
35
|
+
id: string;
|
|
36
|
+
type: ProfileType;
|
|
37
|
+
/** Env vars to overlay on the SDK subprocess environment */
|
|
38
|
+
env: Record<string, string>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set the active profile. All requests without an explicit x-meridian-profile
|
|
42
|
+
* header will use this profile. Persisted to ~/.config/meridian/settings.json.
|
|
43
|
+
*/
|
|
44
|
+
export declare function setActiveProfile(profileId: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get the current active profile ID.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getActiveProfileId(): string | undefined;
|
|
49
|
+
/** Reset active profile — for testing only. */
|
|
50
|
+
export declare function resetActiveProfile(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Load persisted active profile from settings. Called once at startup
|
|
53
|
+
* to restore the user's last selection. Only restores when disk
|
|
54
|
+
* discovery is enabled (i.e. real CLI startup, not tests).
|
|
55
|
+
* Validates the saved profile actually exists before restoring.
|
|
56
|
+
*/
|
|
57
|
+
export declare function restoreActiveProfile(configProfiles?: ProfileConfig[]): void;
|
|
58
|
+
/** Enable disk auto-discovery of profiles. Called by the CLI when
|
|
59
|
+
* no MERIDIAN_PROFILES env var is set, so the server picks up
|
|
60
|
+
* profiles from ~/.config/meridian/profiles.json dynamically. */
|
|
61
|
+
export declare function enableDiskProfileDiscovery(): void;
|
|
62
|
+
export declare function getEffectiveProfiles(configProfiles: ProfileConfig[] | undefined): ProfileConfig[];
|
|
63
|
+
/** Check if any profiles are available from any source */
|
|
64
|
+
export declare function hasProfiles(configProfiles: ProfileConfig[] | undefined): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a profile from the configuration.
|
|
67
|
+
*
|
|
68
|
+
* @param profiles - Configured profiles (from ProxyConfig)
|
|
69
|
+
* @param defaultProfile - Default profile ID (from ProxyConfig)
|
|
70
|
+
* @param requestedId - Explicit profile ID from request header
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveProfile(profiles: ProfileConfig[] | undefined, defaultProfile: string | undefined, requestedId?: string): ResolvedProfile;
|
|
73
|
+
/**
|
|
74
|
+
* Get all configured profile IDs with their types.
|
|
75
|
+
*/
|
|
76
|
+
export declare function listProfiles(profiles: ProfileConfig[] | undefined, defaultProfile: string | undefined): Array<{
|
|
77
|
+
id: string;
|
|
78
|
+
type: ProfileType;
|
|
79
|
+
isActive: boolean;
|
|
80
|
+
}>;
|
|
81
|
+
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/proxy/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAcH;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,EAAE,CAkBtD;AAED,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,KAAK,CAAA;AAE9C,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAA;IACV,oFAAoF;IACpF,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,WAAW,CAAA;IACjB,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC5B;AAOD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAY3E;AAUD;;kEAEkE;AAClE,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,aAAa,EAAE,CAOjG;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,cAAc,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,OAAO,CAEhF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,aAAa,EAAE,GAAG,SAAS,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,CAkBjB;AAqBD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,aAAa,EAAE,GAAG,SAAS,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAU7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAqBvD,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAEzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAoG7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAimDhF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAiEhG"}
|