@neuralnomads/codenomad-dev 0.14.0-dev-20260418-e022a158 → 0.14.0-dev-20260420-04fc28c4
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/dist/index.js +8 -3
- package/dist/server/__tests__/remote-proxy.test.js +204 -0
- package/dist/server/http-server.js +6 -1
- package/dist/server/remote-proxy.js +466 -0
- package/dist/server/routes/remote-proxy.js +42 -0
- package/package.json +1 -1
- package/public/assets/{ChangesTab-DUZlwLiK.js → ChangesTab-eUJ7HXjk.js} +2 -2
- package/public/assets/{DiffToolbar-C32dRoEE.js → DiffToolbar-C2gN4-DU.js} +1 -1
- package/public/assets/{FilesTab-BHR_yoxs.js → FilesTab-BtxCG1pv.js} +2 -2
- package/public/assets/{GitChangesTab-glvFfIqf.js → GitChangesTab-BVOgrozk.js} +2 -2
- package/public/assets/{SplitFilePanel-c1Cyzd2Q.js → SplitFilePanel-vPBNqijZ.js} +1 -1
- package/public/assets/{StatusTab-D_y6grlM.js → StatusTab-BLnPWyWk.js} +1 -1
- package/public/assets/{bundle-full-xErn6pK2.js → bundle-full-Ddu6qye3.js} +1 -1
- package/public/assets/{diff-viewer-Ti4vD-Wf.js → diff-viewer-BZeFsDG4.js} +1 -1
- package/public/assets/{index-D5K3x-5q.js → index-BGjy4SXE.js} +1 -1
- package/public/assets/{index-KGa2MZ03.js → index-BWikFX-R.js} +1 -1
- package/public/assets/{index-DNjsUvJP.js → index-C72ltV-E.js} +1 -1
- package/public/assets/{index-MN-xsoRk.js → index-C_TDxjfc.js} +2 -2
- package/public/assets/{index-RbYx88R2.js → index-CcYvh3Uc.js} +1 -1
- package/public/assets/{index-Buu9pQM-.js → index-CmAwr57o.js} +1 -1
- package/public/assets/{index-DAUGrHIr.js → index-DL8_CQ8W.js} +1 -1
- package/public/assets/{index-Vi334d28.js → index-DoLglUyU.js} +1 -1
- package/public/assets/{index-DCKsvmLK.js → index-lqTLZJ_z.js} +1 -1
- package/public/assets/{loading-8z6r7QGU.js → loading-CXx1HTRq.js} +1 -1
- package/public/assets/main-DAirHb0u.js +48 -0
- package/public/assets/{markdown-CN__9g8I.js → markdown-CB_rJhcV.js} +3 -3
- package/public/assets/{monaco-viewer-C8arwHE9.js → monaco-viewer-BAhYjr-N.js} +4 -4
- package/public/assets/{todo-CGjayFGz.js → todo-CAxz-1Tz.js} +1 -1
- package/public/assets/{tool-call-Wyw279OP.js → tool-call-ZqXDG9uG.js} +3 -3
- package/public/assets/{unified-picker-DqT__5EQ.js → unified-picker-d0K5E9QI.js} +1 -1
- package/public/assets/{wrap-text-DJEP0aF1.js → wrap-text-CPc0o1wr.js} +1 -1
- package/public/index.html +3 -3
- package/public/loading.html +3 -3
- package/public/sw.js +1 -1
- package/public/assets/main-BL6QgWzz.js +0 -48
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
3
|
+
import { Readable } from "stream";
|
|
4
|
+
import { pipeline } from "stream/promises";
|
|
5
|
+
import { Agent, fetch } from "undici";
|
|
6
|
+
const LOOPBACK_HOST = "127.0.0.1";
|
|
7
|
+
const BOOTSTRAP_PAGE_PATH = "/__codenomad/auth/token";
|
|
8
|
+
const BOOTSTRAP_EXCHANGE_PATH = "/__codenomad/api/auth/token";
|
|
9
|
+
const SESSION_IDLE_TTL_MS = 30 * 60000;
|
|
10
|
+
export class RemoteProxySessionManager {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.sessions = new Map();
|
|
14
|
+
this.cleanupTimer = setInterval(() => {
|
|
15
|
+
void this.cleanupExpiredSessions();
|
|
16
|
+
}, 60000);
|
|
17
|
+
this.cleanupTimer.unref();
|
|
18
|
+
}
|
|
19
|
+
async createSession(baseUrl, skipTlsVerify) {
|
|
20
|
+
if (!this.options.httpsOptions) {
|
|
21
|
+
throw new Error("Local HTTPS is required for remote proxy sessions");
|
|
22
|
+
}
|
|
23
|
+
const targetBaseUrl = normalizeBaseUrl(baseUrl);
|
|
24
|
+
const sessionId = randomUUID();
|
|
25
|
+
const bootstrapToken = randomBytes(32).toString("base64url");
|
|
26
|
+
const dispatcher = skipTlsVerify ? new Agent({ connect: { rejectUnauthorized: false } }) : undefined;
|
|
27
|
+
const app = Fastify({ logger: false, https: this.options.httpsOptions });
|
|
28
|
+
let session = null;
|
|
29
|
+
app.removeAllContentTypeParsers();
|
|
30
|
+
// Preserve raw request bodies for proxying while still letting token JSON parse from Buffer.
|
|
31
|
+
app.addContentTypeParser("*", { parseAs: "buffer" }, (_req, body, done) => done(null, body));
|
|
32
|
+
app.get(BOOTSTRAP_PAGE_PATH, async (request, reply) => {
|
|
33
|
+
if (!this.options.authManager.isLoopbackRequest(request)) {
|
|
34
|
+
reply.code(404).send({ error: "Not found" });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
reply.header("Cache-Control", "no-store");
|
|
38
|
+
reply.header("Pragma", "no-cache");
|
|
39
|
+
reply.header("Expires", "0");
|
|
40
|
+
reply.type("text/html").send(buildBootstrapPageHtml());
|
|
41
|
+
});
|
|
42
|
+
app.post(BOOTSTRAP_EXCHANGE_PATH, async (request, reply) => {
|
|
43
|
+
if (!this.options.authManager.isLoopbackRequest(request)) {
|
|
44
|
+
reply.code(404).send({ error: "Not found" });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!session) {
|
|
48
|
+
reply.code(503).send({ error: "Remote proxy session is unavailable" });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const body = parseTokenBody(request.body);
|
|
52
|
+
if (body.token !== session.bootstrapToken) {
|
|
53
|
+
reply.code(401).send({ error: "Invalid token" });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
session.activated = true;
|
|
57
|
+
session.lastAccessAt = Date.now();
|
|
58
|
+
reply.send({ ok: true });
|
|
59
|
+
});
|
|
60
|
+
app.all("/*", async (request, reply) => {
|
|
61
|
+
if (!session) {
|
|
62
|
+
reply.code(503).send({ error: "Remote proxy session is unavailable" });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (!session.activated) {
|
|
66
|
+
reply.code(403).send({ error: "Remote proxy session is not activated" });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
session.lastAccessAt = Date.now();
|
|
70
|
+
await proxyRequest({ request, reply, session, logger: this.options.logger });
|
|
71
|
+
});
|
|
72
|
+
app.setNotFoundHandler(async (request, reply) => {
|
|
73
|
+
if (!session) {
|
|
74
|
+
reply.code(503).send({ error: "Remote proxy session is unavailable" });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!session.activated) {
|
|
78
|
+
reply.code(403).send({ error: "Remote proxy session is not activated" });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
session.lastAccessAt = Date.now();
|
|
82
|
+
await proxyRequest({ request, reply, session, logger: this.options.logger });
|
|
83
|
+
});
|
|
84
|
+
const addressInfo = await app.listen({ host: LOOPBACK_HOST, port: 0 });
|
|
85
|
+
const address = new URL(addressInfo);
|
|
86
|
+
const localBaseUrl = new URL(`https://${LOOPBACK_HOST}:${address.port}`);
|
|
87
|
+
const entryUrl = new URL(targetBaseUrl.pathname || "/", localBaseUrl);
|
|
88
|
+
const returnTo = buildReturnToTarget(entryUrl);
|
|
89
|
+
session = {
|
|
90
|
+
id: sessionId,
|
|
91
|
+
bootstrapToken,
|
|
92
|
+
targetBaseUrl,
|
|
93
|
+
skipTlsVerify,
|
|
94
|
+
localBaseUrl,
|
|
95
|
+
entryUrl,
|
|
96
|
+
bootstrapUrl: `${localBaseUrl.origin}${BOOTSTRAP_PAGE_PATH}?returnTo=${encodeURIComponent(returnTo)}#${encodeURIComponent(bootstrapToken)}`,
|
|
97
|
+
activated: false,
|
|
98
|
+
cookiePrefix: `cnrp_${randomBytes(6).toString("hex")}_`,
|
|
99
|
+
app,
|
|
100
|
+
dispatcher,
|
|
101
|
+
createdAt: Date.now(),
|
|
102
|
+
lastAccessAt: Date.now(),
|
|
103
|
+
};
|
|
104
|
+
this.sessions.set(sessionId, session);
|
|
105
|
+
this.options.logger.info({ sessionId, targetBaseUrl: targetBaseUrl.toString(), localBaseUrl: localBaseUrl.toString() }, "Created remote proxy session");
|
|
106
|
+
return { sessionId, windowUrl: session.bootstrapUrl };
|
|
107
|
+
}
|
|
108
|
+
async deleteSession(sessionId) {
|
|
109
|
+
return this.disposeSession(sessionId);
|
|
110
|
+
}
|
|
111
|
+
async cleanupExpiredSessions() {
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
for (const session of Array.from(this.sessions.values())) {
|
|
114
|
+
if (now - session.lastAccessAt <= SESSION_IDLE_TTL_MS) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
await this.disposeSession(session.id);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async disposeSession(sessionId) {
|
|
121
|
+
const session = this.sessions.get(sessionId);
|
|
122
|
+
if (!session) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
this.sessions.delete(sessionId);
|
|
126
|
+
session.dispatcher?.close().catch(() => { });
|
|
127
|
+
await session.app.close().catch(() => { });
|
|
128
|
+
this.options.logger.info({ sessionId }, "Disposed remote proxy session");
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function normalizeBaseUrl(input) {
|
|
133
|
+
const parsed = new URL(input.trim());
|
|
134
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
135
|
+
throw new Error("Server URL must use http:// or https://");
|
|
136
|
+
}
|
|
137
|
+
parsed.hash = "";
|
|
138
|
+
parsed.search = "";
|
|
139
|
+
parsed.pathname = parsed.pathname === "/" ? "/" : parsed.pathname.replace(/\/+$/, "") || "/";
|
|
140
|
+
return parsed;
|
|
141
|
+
}
|
|
142
|
+
function buildReturnToTarget(entryUrl) {
|
|
143
|
+
const query = entryUrl.search ? entryUrl.search : "";
|
|
144
|
+
return `${entryUrl.pathname || "/"}${query}`;
|
|
145
|
+
}
|
|
146
|
+
function buildBootstrapPageHtml() {
|
|
147
|
+
return `<!doctype html>
|
|
148
|
+
<html lang="en">
|
|
149
|
+
<head>
|
|
150
|
+
<meta charset="utf-8" />
|
|
151
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
152
|
+
<title>CodeNomad</title>
|
|
153
|
+
<style>
|
|
154
|
+
body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; background: #0b0b0f; color: #fff; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
|
155
|
+
.card { width: 420px; max-width: calc(100vw - 32px); background: #14141c; border: 1px solid rgba(255,255,255,0.08); border-radius: 14px; padding: 24px; }
|
|
156
|
+
h1 { font-size: 18px; margin: 0 0 12px; }
|
|
157
|
+
p { margin: 0; color: rgba(255,255,255,0.7); font-size: 13px; line-height: 1.4; }
|
|
158
|
+
.error { margin-top: 12px; color: #ff6b6b; font-size: 13px; display: none; }
|
|
159
|
+
</style>
|
|
160
|
+
</head>
|
|
161
|
+
<body>
|
|
162
|
+
<div class="card">
|
|
163
|
+
<h1>Connecting...</h1>
|
|
164
|
+
<p>Finalizing local authentication.</p>
|
|
165
|
+
<div id="error" class="error"></div>
|
|
166
|
+
</div>
|
|
167
|
+
<script>
|
|
168
|
+
const token = decodeURIComponent((location.hash || "").replace(/^#/, "").trim())
|
|
169
|
+
const params = new URLSearchParams(location.search)
|
|
170
|
+
const returnTo = sanitizeReturnTo(params.get("returnTo"))
|
|
171
|
+
const errorEl = document.getElementById("error")
|
|
172
|
+
|
|
173
|
+
function sanitizeReturnTo(value) {
|
|
174
|
+
if (!value || typeof value !== "string") return "/"
|
|
175
|
+
if (!value.startsWith("/")) return "/"
|
|
176
|
+
if (value.startsWith("//")) return "/"
|
|
177
|
+
return value
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function showError(message) {
|
|
181
|
+
errorEl.textContent = message
|
|
182
|
+
errorEl.style.display = "block"
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function run() {
|
|
186
|
+
if (!token) {
|
|
187
|
+
showError("Missing bootstrap token.")
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const res = await fetch("${BOOTSTRAP_EXCHANGE_PATH}", {
|
|
193
|
+
method: "POST",
|
|
194
|
+
headers: { "Content-Type": "application/json" },
|
|
195
|
+
body: JSON.stringify({ token }),
|
|
196
|
+
credentials: "include",
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
if (!res.ok) {
|
|
200
|
+
let message = ""
|
|
201
|
+
try {
|
|
202
|
+
const json = await res.json()
|
|
203
|
+
message = json && json.error ? String(json.error) : ""
|
|
204
|
+
} catch {
|
|
205
|
+
message = ""
|
|
206
|
+
}
|
|
207
|
+
showError(message || "Token exchange failed (" + res.status + ")")
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
window.location.replace(returnTo)
|
|
212
|
+
} catch (error) {
|
|
213
|
+
showError(error && error.message ? error.message : String(error))
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
run()
|
|
218
|
+
</script>
|
|
219
|
+
</body>
|
|
220
|
+
</html>`;
|
|
221
|
+
}
|
|
222
|
+
function parseTokenBody(body) {
|
|
223
|
+
const value = normalizeJsonBody(body);
|
|
224
|
+
const token = typeof value?.token === "string" ? value.token.trim() : "";
|
|
225
|
+
if (!token) {
|
|
226
|
+
throw new Error("Missing bootstrap token");
|
|
227
|
+
}
|
|
228
|
+
return { token };
|
|
229
|
+
}
|
|
230
|
+
function normalizeJsonBody(body) {
|
|
231
|
+
if (Buffer.isBuffer(body)) {
|
|
232
|
+
return JSON.parse(body.toString("utf-8"));
|
|
233
|
+
}
|
|
234
|
+
if (typeof body === "string") {
|
|
235
|
+
return JSON.parse(body);
|
|
236
|
+
}
|
|
237
|
+
return body;
|
|
238
|
+
}
|
|
239
|
+
function toRequestBody(body) {
|
|
240
|
+
if (body == null) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
if (Buffer.isBuffer(body) || typeof body === "string" || body instanceof Uint8Array) {
|
|
244
|
+
return body;
|
|
245
|
+
}
|
|
246
|
+
return JSON.stringify(body);
|
|
247
|
+
}
|
|
248
|
+
async function proxyRequest(args) {
|
|
249
|
+
const { request, reply, session, logger } = args;
|
|
250
|
+
const upstreamUrl = buildUpstreamUrl(session.targetBaseUrl, request.raw.url ?? request.url);
|
|
251
|
+
const headers = filterRequestHeaders(request.headers, session);
|
|
252
|
+
const init = {
|
|
253
|
+
method: request.method,
|
|
254
|
+
headers,
|
|
255
|
+
dispatcher: session.dispatcher,
|
|
256
|
+
redirect: "manual",
|
|
257
|
+
};
|
|
258
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
259
|
+
const body = toRequestBody(request.body);
|
|
260
|
+
if (body !== undefined) {
|
|
261
|
+
init.body = body;
|
|
262
|
+
init.duplex = "half";
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const response = await fetch(upstreamUrl, init);
|
|
267
|
+
reply.code(response.status);
|
|
268
|
+
applyResponseHeaders(reply, response, session);
|
|
269
|
+
if (!response.body || request.method === "HEAD") {
|
|
270
|
+
reply.send();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
reply.hijack();
|
|
274
|
+
reply.raw.writeHead(reply.statusCode, toOutgoingHeaders(reply.getHeaders()));
|
|
275
|
+
await pipeline(Readable.fromWeb(response.body), reply.raw);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
logger.error({ err: error, upstreamUrl }, "Failed to proxy remote session request");
|
|
279
|
+
if (!reply.sent) {
|
|
280
|
+
reply.code(502).send({ error: "Remote proxy request failed" });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function buildUpstreamUrl(baseUrl, rawUrl) {
|
|
285
|
+
const parsed = new URL(rawUrl, "https://localhost");
|
|
286
|
+
const url = new URL(baseUrl.toString());
|
|
287
|
+
url.pathname = rewriteRequestPath(baseUrl, parsed.pathname);
|
|
288
|
+
url.search = stripInternalQuery(parsed.search);
|
|
289
|
+
url.hash = "";
|
|
290
|
+
return url.toString();
|
|
291
|
+
}
|
|
292
|
+
function rewriteRequestPath(baseUrl, requestPath) {
|
|
293
|
+
const basePath = normalizedBasePath(baseUrl);
|
|
294
|
+
if (basePath === "/") {
|
|
295
|
+
return requestPath;
|
|
296
|
+
}
|
|
297
|
+
if (requestPath === "/") {
|
|
298
|
+
return basePath;
|
|
299
|
+
}
|
|
300
|
+
if (pathHasBasePrefix(basePath, requestPath)) {
|
|
301
|
+
return requestPath;
|
|
302
|
+
}
|
|
303
|
+
return `${basePath}${requestPath}`;
|
|
304
|
+
}
|
|
305
|
+
function normalizedBasePath(baseUrl) {
|
|
306
|
+
return baseUrl.pathname || "/";
|
|
307
|
+
}
|
|
308
|
+
function pathHasBasePrefix(basePath, requestPath) {
|
|
309
|
+
return requestPath === basePath || requestPath.startsWith(`${basePath}/`);
|
|
310
|
+
}
|
|
311
|
+
function stripInternalQuery(search) {
|
|
312
|
+
if (!search || search === "?") {
|
|
313
|
+
return "";
|
|
314
|
+
}
|
|
315
|
+
return search;
|
|
316
|
+
}
|
|
317
|
+
function filterRequestHeaders(headers, session) {
|
|
318
|
+
const next = {};
|
|
319
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
320
|
+
if (!value)
|
|
321
|
+
continue;
|
|
322
|
+
const lower = key.toLowerCase();
|
|
323
|
+
if (isHopByHopHeader(lower) ||
|
|
324
|
+
lower === "host" ||
|
|
325
|
+
lower === "content-length" ||
|
|
326
|
+
lower === "accept-encoding") {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (lower === "origin") {
|
|
330
|
+
next[key] = session.targetBaseUrl.origin;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (lower === "referer") {
|
|
334
|
+
const rewritten = rewriteRefererHeader(Array.isArray(value) ? value[0] : value, session.targetBaseUrl);
|
|
335
|
+
if (rewritten) {
|
|
336
|
+
next[key] = rewritten;
|
|
337
|
+
}
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (lower === "cookie") {
|
|
341
|
+
const rewritten = rewriteRequestCookieHeader(Array.isArray(value) ? value.join("; ") : value, session.cookiePrefix);
|
|
342
|
+
if (rewritten) {
|
|
343
|
+
next[key] = rewritten;
|
|
344
|
+
}
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
next[key] = Array.isArray(value) ? value.join(",") : value;
|
|
348
|
+
}
|
|
349
|
+
next.host = session.targetBaseUrl.port ? `${session.targetBaseUrl.hostname}:${session.targetBaseUrl.port}` : session.targetBaseUrl.hostname;
|
|
350
|
+
if (!next.origin) {
|
|
351
|
+
next.origin = session.targetBaseUrl.origin;
|
|
352
|
+
}
|
|
353
|
+
return next;
|
|
354
|
+
}
|
|
355
|
+
function rewriteRefererHeader(referer, targetBaseUrl) {
|
|
356
|
+
if (!referer) {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
const parsed = new URL(referer);
|
|
361
|
+
const rewritten = new URL(targetBaseUrl.toString());
|
|
362
|
+
rewritten.pathname = rewriteRequestPath(targetBaseUrl, parsed.pathname);
|
|
363
|
+
rewritten.search = parsed.search;
|
|
364
|
+
rewritten.hash = parsed.hash;
|
|
365
|
+
return rewritten.toString();
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function applyResponseHeaders(reply, response, session) {
|
|
372
|
+
const setCookie = response.headers.getSetCookie?.();
|
|
373
|
+
if (Array.isArray(setCookie)) {
|
|
374
|
+
for (const cookie of setCookie) {
|
|
375
|
+
reply.header("set-cookie", rewriteSetCookie(cookie, session.cookiePrefix));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
response.headers.forEach((value, key) => {
|
|
379
|
+
const lower = key.toLowerCase();
|
|
380
|
+
if (isHopByHopHeader(lower) ||
|
|
381
|
+
lower === "set-cookie" ||
|
|
382
|
+
lower === "content-length" ||
|
|
383
|
+
lower === "content-encoding") {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (lower === "location") {
|
|
387
|
+
reply.header(key, rewriteLocation(value, session.targetBaseUrl, session.localBaseUrl));
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
reply.header(key, value);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function toOutgoingHeaders(headers) {
|
|
394
|
+
const next = {};
|
|
395
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
396
|
+
if (value === undefined) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
next[key] = Array.isArray(value) ? value.map(String) : String(value);
|
|
400
|
+
}
|
|
401
|
+
return next;
|
|
402
|
+
}
|
|
403
|
+
function rewriteSetCookie(cookie, cookiePrefix) {
|
|
404
|
+
const parts = cookie.split(";").map((part) => part.trim());
|
|
405
|
+
const first = parts.shift() ?? "";
|
|
406
|
+
const separator = first.indexOf("=");
|
|
407
|
+
if (separator <= 0) {
|
|
408
|
+
return cookie;
|
|
409
|
+
}
|
|
410
|
+
const name = first.slice(0, separator).trim();
|
|
411
|
+
const value = first.slice(separator + 1);
|
|
412
|
+
const rewritten = [`${cookiePrefix}${name}=${value}`];
|
|
413
|
+
for (const part of parts) {
|
|
414
|
+
if (part.slice(0, 7).toLowerCase().startsWith("domain=")) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
rewritten.push(part);
|
|
418
|
+
}
|
|
419
|
+
return rewritten.join("; ");
|
|
420
|
+
}
|
|
421
|
+
function rewriteRequestCookieHeader(cookieHeader, cookiePrefix) {
|
|
422
|
+
const next = [];
|
|
423
|
+
for (const rawPart of cookieHeader.split(";")) {
|
|
424
|
+
const part = rawPart.trim();
|
|
425
|
+
if (!part)
|
|
426
|
+
continue;
|
|
427
|
+
const separator = part.indexOf("=");
|
|
428
|
+
if (separator <= 0)
|
|
429
|
+
continue;
|
|
430
|
+
const name = part.slice(0, separator).trim();
|
|
431
|
+
const value = part.slice(separator + 1);
|
|
432
|
+
if (!name.startsWith(cookiePrefix)) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
next.push(`${name.slice(cookiePrefix.length)}=${value}`);
|
|
436
|
+
}
|
|
437
|
+
return next.join("; ");
|
|
438
|
+
}
|
|
439
|
+
function rewriteLocation(location, targetBaseUrl, localBaseUrl) {
|
|
440
|
+
try {
|
|
441
|
+
const parsed = new URL(location, targetBaseUrl);
|
|
442
|
+
if (parsed.origin !== targetBaseUrl.origin) {
|
|
443
|
+
return location;
|
|
444
|
+
}
|
|
445
|
+
const rewritten = new URL(localBaseUrl.toString());
|
|
446
|
+
rewritten.pathname = parsed.pathname;
|
|
447
|
+
rewritten.search = parsed.search;
|
|
448
|
+
rewritten.hash = parsed.hash;
|
|
449
|
+
return rewritten.toString();
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
return location;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function isHopByHopHeader(name) {
|
|
456
|
+
return new Set([
|
|
457
|
+
"connection",
|
|
458
|
+
"keep-alive",
|
|
459
|
+
"proxy-authenticate",
|
|
460
|
+
"proxy-authorization",
|
|
461
|
+
"te",
|
|
462
|
+
"trailer",
|
|
463
|
+
"transfer-encoding",
|
|
464
|
+
"upgrade",
|
|
465
|
+
]).has(name);
|
|
466
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isLoopbackAddress } from "../../auth/http-auth";
|
|
3
|
+
const CreateSessionSchema = z.object({
|
|
4
|
+
baseUrl: z.string().min(1),
|
|
5
|
+
skipTlsVerify: z.boolean().optional(),
|
|
6
|
+
});
|
|
7
|
+
const SessionParamsSchema = z.object({
|
|
8
|
+
id: z.string().uuid(),
|
|
9
|
+
});
|
|
10
|
+
export function registerRemoteProxyRoutes(app, deps) {
|
|
11
|
+
app.post("/api/remote-proxy/sessions", async (request, reply) => {
|
|
12
|
+
try {
|
|
13
|
+
const body = CreateSessionSchema.parse(request.body ?? {});
|
|
14
|
+
return await deps.sessionManager.createSession(body.baseUrl, Boolean(body.skipTlsVerify));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
deps.logger.warn({ err: error }, "Failed to create remote proxy session");
|
|
18
|
+
reply.code(400);
|
|
19
|
+
return { error: error instanceof Error ? error.message : "Failed to create remote proxy session" };
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
app.delete("/api/remote-proxy/sessions/:id", async (request, reply) => {
|
|
23
|
+
if (!isLoopbackAddress(request.socket.remoteAddress)) {
|
|
24
|
+
reply.code(404);
|
|
25
|
+
return { error: "Not found" };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const params = SessionParamsSchema.parse(request.params ?? {});
|
|
29
|
+
const deleted = await deps.sessionManager.deleteSession(params.id);
|
|
30
|
+
if (!deleted) {
|
|
31
|
+
reply.code(404);
|
|
32
|
+
return { error: "Remote proxy session not found" };
|
|
33
|
+
}
|
|
34
|
+
return { ok: true };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
deps.logger.warn({ err: error }, "Failed to delete remote proxy session");
|
|
38
|
+
reply.code(400);
|
|
39
|
+
return { error: error instanceof Error ? error.message : "Failed to delete remote proxy session" };
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-
|
|
2
|
-
import{_ as K}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-BAhYjr-N.js","assets/git-diff-vendor-CSgooKT_.js","assets/fast-diff-vendor-DgdwVvTQ.js","assets/highlight-vendor-8FKMu9os.js","assets/git-diff-vendor-HAZkIolJ.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as K}from"./index-C_TDxjfc.js";import{m as B,t as g,i as a,d as w,a as F,f as N}from"./monaco-viewer-BAhYjr-N.js";import{c as f,n as c,a as L,F as T,S as W,z as j,A as q}from"./git-diff-vendor-CSgooKT_.js";import{D as G}from"./DiffToolbar-C2gN4-DU.js";import{S as H}from"./SplitFilePanel-vPBNqijZ.js";import"./fast-diff-vendor-DgdwVvTQ.js";import"./highlight-vendor-8FKMu9os.js";import"./main-DAirHb0u.js";import"./wrap-text-CPc0o1wr.js";var J=g('<div class="file-viewer-panel flex-1"><div class="file-viewer-content file-viewer-content--monaco">'),p=g("<div class=file-viewer-empty><span class=file-viewer-empty-text>"),Q=g('<div class="p-3 text-xs text-secondary">'),E=g("<div><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text></span></div><div class=file-list-item-stats><span class=file-list-item-additions>+</span><span class=file-list-item-deletions>-"),U=g("<span class=files-tab-selected-path><span class=file-path-text>"),X=g('<div class=files-tab-stats style="flex:0 0 auto"><span class="files-tab-stat files-tab-stat-additions"><span class=files-tab-stat-value>+</span></span><span class="files-tab-stat files-tab-stat-deletions"><span class=files-tab-stat-value>-'),Y=g("<div style=margin-left:auto>");const Z=q(()=>K(()=>import("./monaco-viewer-BAhYjr-N.js").then(e=>e.ad),__vite__mapDeps([0,1,2,3,4])).then(e=>({default:e.MonacoDiffViewer}))),fe=e=>{const M=f(()=>e.activeSessionId()),S=f(()=>!!(M()&&M()!=="info")),D=f(()=>S()?e.activeSessionDiffs():null),m=f(()=>{const n=D();return Array.isArray(n)?[...n].sort((i,l)=>String(i.file||"").localeCompare(String(l.file||""))):[]}),R=f(()=>m().reduce((n,i)=>(n.additions+=typeof i.additions=="number"?i.additions:0,n.deletions+=typeof i.deletions=="number"?i.deletions:0,n),{additions:0,deletions:0})),I=f(()=>{const n=m();return n.length===0?null:n.reduce((i,l)=>{const v=typeof(i==null?void 0:i.additions)=="number"?i.additions:0,y=typeof(i==null?void 0:i.deletions)=="number"?i.deletions:0,x=v+y,k=typeof(l==null?void 0:l.additions)=="number"?l.additions:0,t=typeof(l==null?void 0:l.deletions)=="number"?l.deletions:0,r=k+t;return r>x?l:r<x?i:String(l.file||"").localeCompare(String((i==null?void 0:i.file)||""))<0?l:i},n[0])}),P=f(()=>{const n=e.selectedFile(),i=m();if(n){const l=i.find(v=>v.file===n);if(l)return l}return I()}),O=f(()=>`${e.instanceId}:${S()?M():"no-session"}`),V=f(()=>{if(!S())return e.t("instanceShell.sessionChanges.noSessionSelected");const n=D();return n===void 0?e.t("instanceShell.sessionChanges.loading"):!Array.isArray(n)||n.length===0?e.t("instanceShell.sessionChanges.empty"):e.t("instanceShell.filesShell.viewerEmpty")}),A=f(()=>{const n=P();return n!=null&&n.file?String(n.file):e.t("instanceShell.rightPanel.tabs.changes")});return B(()=>{const n=m(),i=R(),l=P(),v=()=>(()=>{var t=J(),r=t.firstChild;return a(r,c(W,{get when(){return l&&S()&&n.length>0?l:null},get fallback(){return(()=>{var d=p(),s=d.firstChild;return a(s,V),d})()},children:d=>c(j,{get fallback(){return(()=>{var s=p(),u=s.firstChild;return a(u,()=>e.t("instanceInfo.loading")),s})()},get children(){return c(Z,{get scopeKey(){return O()},get path(){return String(d().file||"")},get patch(){return String(d().patch||"")},get viewMode(){return e.diffViewMode()},get contextMode(){return e.diffContextMode()},get wordWrap(){return e.diffWordWrapMode()}})}})})),t})(),y=()=>(()=>{var t=Q();return a(t,V),t})();return c(H,{get header(){return[(()=>{var t=U(),r=t.firstChild;return a(r,A),L(()=>w(t,"title",A())),t})(),(()=>{var t=X(),r=t.firstChild,d=r.firstChild;d.firstChild;var s=r.nextSibling,u=s.firstChild;return u.firstChild,a(d,()=>i.additions,null),a(u,()=>i.deletions,null),t})(),(()=>{var t=Y();return a(t,c(G,{get viewMode(){return e.diffViewMode()},get contextMode(){return e.diffContextMode()},get wordWrapMode(){return e.diffWordWrapMode()},get onViewModeChange(){return e.onViewModeChange},get onContextModeChange(){return e.onContextModeChange},get onWordWrapModeChange(){return e.onWordWrapModeChange}})),t})()]},list:{panel:()=>c(W,{get when(){return n.length>0},get fallback(){return y()},get children(){return c(T,{each:n,children:t=>(()=>{var r=E(),d=r.firstChild,s=d.firstChild,u=s.firstChild,b=s.nextSibling,h=b.firstChild;h.firstChild;var C=h.nextSibling;return C.firstChild,r.$$click=()=>{e.onSelectFile(t.file,e.isPhoneLayout())},a(u,()=>t.file),a(h,()=>t.additions,null),a(C,()=>t.deletions,null),L(o=>{var _=`file-list-item ${(l==null?void 0:l.file)===t.file?"file-list-item-active":""}`,$=t.file;return _!==o.e&&F(r,o.e=_),$!==o.t&&w(s,"title",o.t=$),o},{e:void 0,t:void 0}),r})()})}}),overlay:()=>c(W,{get when(){return n.length>0},get fallback(){return y()},get children(){return c(T,{each:n,children:t=>(()=>{var r=E(),d=r.firstChild,s=d.firstChild,u=s.firstChild,b=s.nextSibling,h=b.firstChild;h.firstChild;var C=h.nextSibling;return C.firstChild,r.$$click=()=>{e.onSelectFile(t.file,!0)},a(u,()=>t.file),a(h,()=>t.additions,null),a(C,()=>t.deletions,null),L(o=>{var _=`file-list-item ${(l==null?void 0:l.file)===t.file?"file-list-item-active":""}`,$=t.file,z=t.file;return _!==o.e&&F(r,o.e=_),$!==o.t&&w(r,"title",o.t=$),z!==o.a&&w(s,"title",o.a=z),o},{e:void 0,t:void 0,a:void 0}),r})()})}})},get viewer(){return v()},get listOpen(){return e.listOpen()},get onToggleList(){return e.onToggleList},get splitWidth(){return e.splitWidth()},get onResizeMouseDown(){return e.onResizeMouseDown},get onResizeTouchStart(){return e.onResizeTouchStart},get isPhoneLayout(){return e.isPhoneLayout()},get overlayAriaLabel(){return e.t("instanceShell.rightPanel.tabs.changes")}})})};N(["click"]);export{fe as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as g,i as c,m as W,d as i,a as S,f as T}from"./monaco-viewer-
|
|
1
|
+
import{t as g,i as c,m as W,d as i,a as S,f as T}from"./monaco-viewer-BAhYjr-N.js";import{u as C}from"./index-C_TDxjfc.js";import{n as o,m as $,a as V}from"./git-diff-vendor-CSgooKT_.js";import{I as U,S as A,T as I}from"./main-DAirHb0u.js";import{A as D,W as E}from"./wrap-text-CPc0o1wr.js";const F=[["path",{d:"M12 22v-6",key:"6o8u61"}],["path",{d:"M12 8V2",key:"1wkif3"}],["path",{d:"M4 12H2",key:"rhcxmi"}],["path",{d:"M10 12H8",key:"s88cx1"}],["path",{d:"M16 12h-2",key:"10asgb"}],["path",{d:"M22 12h-2",key:"14jgyd"}],["path",{d:"m15 19-3 3-3-3",key:"11eu04"}],["path",{d:"m15 5-3-3-3 3",key:"itvq4r"}]],H=t=>o(U,$(t,{name:"UnfoldVertical",iconNode:F}));var N=g("<div class=file-viewer-toolbar><button type=button class=file-viewer-toolbar-icon-button></button><button type=button class=file-viewer-toolbar-icon-button></button><button type=button>");const z=t=>{const{t:a}=C(),r=()=>t.viewMode==="split"?"unified":"split",s=()=>t.contextMode==="collapsed"?"expanded":"collapsed",h=()=>t.wordWrapMode==="on"?"off":"on",f=()=>r()==="split"?a("instanceShell.diff.switchToSplit"):a("instanceShell.diff.switchToUnified"),v=()=>s()==="collapsed"?a("instanceShell.diff.hideUnchanged"):a("instanceShell.diff.showFull"),u=()=>h()==="on"?a("instanceShell.diff.enableWordWrap"):a("instanceShell.diff.disableWordWrap");return(()=>{var b=N(),n=b.firstChild,l=n.nextSibling,d=l.nextSibling;return n.$$click=()=>t.onViewModeChange(r()),c(n,(()=>{var e=W(()=>r()==="split");return()=>e()?o(A,{class:"h-4 w-4","aria-hidden":"true"}):o(D,{class:"h-4 w-4","aria-hidden":"true"})})()),l.$$click=()=>t.onContextModeChange(s()),c(l,(()=>{var e=W(()=>s()==="collapsed");return()=>e()?o(I,{class:"h-4 w-4","aria-hidden":"true"}):o(H,{class:"h-4 w-4","aria-hidden":"true"})})()),d.$$click=()=>t.onWordWrapModeChange(h()),c(d,o(E,{class:"h-4 w-4","aria-hidden":"true"})),V(e=>{var m=f(),w=f(),M=v(),p=v(),x=`file-viewer-toolbar-icon-button${t.wordWrapMode==="on"?" active":""}`,k=u(),y=u();return m!==e.e&&i(n,"aria-label",e.e=m),w!==e.t&&i(n,"title",e.t=w),M!==e.a&&i(l,"aria-label",e.a=M),p!==e.o&&i(l,"title",e.o=p),x!==e.i&&S(d,e.i=x),k!==e.n&&i(d,"aria-label",e.n=k),y!==e.s&&i(d,"title",e.s=y),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0}),b})()};T(["click"]);export{z as D};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-
|
|
2
|
-
import{_ as R}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-BAhYjr-N.js","assets/git-diff-vendor-CSgooKT_.js","assets/fast-diff-vendor-DgdwVvTQ.js","assets/highlight-vendor-8FKMu9os.js","assets/git-diff-vendor-HAZkIolJ.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as R}from"./index-C_TDxjfc.js";import{m as _,t as o,i as s,d as c,a as z,f as I}from"./monaco-viewer-BAhYjr-N.js";import{n as i,m as D,S as d,a as v,F,z as V,A as M}from"./git-diff-vendor-CSgooKT_.js";import{S as T}from"./SplitFilePanel-vPBNqijZ.js";import{I as A,R as y}from"./main-DAirHb0u.js";import"./fast-diff-vendor-DgdwVvTQ.js";import"./highlight-vendor-8FKMu9os.js";const O=[["path",{d:"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z",key:"1owoqh"}],["polyline",{points:"17 21 17 13 7 13 7 21",key:"1md35c"}],["polyline",{points:"7 3 7 8 15 8",key:"8nz8an"}]],q=e=>i(A,D(e,{name:"Save",iconNode:O}));var g=o("<div class=file-viewer-empty><span class=file-viewer-empty-text>"),K=o('<div class="file-viewer-panel flex-1"><div class="file-viewer-content file-viewer-content--monaco">'),N=o('<div class="p-3 text-xs text-secondary">'),W=o("<div class=file-list-item><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text>.."),H=o('<div><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text></span></div><div class=file-list-item-stats><span class="text-[10px] text-secondary">'),j=o("<span>"),B=o("<div class=files-tab-stats><span class=files-tab-stat><span class=files-tab-selected-path><span class=file-path-text>"),G=o("<button type=button class=files-header-icon-button style=margin-inline-start:auto>"),J=o("<button type=button class=files-header-icon-button>"),Q=o("<span class=text-error>");const U=M(()=>R(()=>import("./monaco-viewer-BAhYjr-N.js").then(e=>e.ae),__vite__mapDeps([0,1,2,3,4])).then(e=>({default:e.MonacoFileViewer}))),ae=e=>{const C=()=>{const h=e.browserSelectedContent();h!=null&&e.onSave(h)};return _(()=>{const h=e.browserEntries(),P=[...h||[]].sort((t,n)=>{const r=t.type==="directory"?0:1,l=n.type==="directory"?0:1;return r!==l?r-l:String(t.name||"").localeCompare(String(n.name||""))}),L=e.parentPath(),w=()=>e.browserSelectedPath()||e.browserPath(),x=()=>e.browserLoading()&&h===null?e.t("instanceInfo.loading"):e.t("instanceShell.filesShell.viewerEmpty"),k=()=>(()=>{var t=K(),n=t.firstChild;return s(n,i(d,{get when(){return e.browserSelectedLoading()},get fallback(){return i(d,{get when(){return e.browserSelectedError()},get fallback(){return i(d,{get when(){return _(()=>!!(e.browserSelectedPath()&&e.browserSelectedContent()!==null))()?{path:e.browserSelectedPath(),content:e.browserSelectedContent()}:null},get fallback(){return(()=>{var r=g(),l=r.firstChild;return s(l,x),r})()},children:r=>i(V,{get fallback(){return(()=>{var l=g(),a=l.firstChild;return s(a,()=>e.t("instanceInfo.loading")),l})()},get children(){return i(U,{get scopeKey(){return e.scopeKey()},get path(){return r().path},get content(){return r().content},get onSave(){return e.onSave},get onContentChange(){return e.onContentChange}})}})})},children:r=>(()=>{var l=g(),a=l.firstChild;return s(a,r),l})()})},get children(){var r=g(),l=r.firstChild;return s(l,()=>e.t("instanceInfo.loading")),r}})),t})(),m=()=>[i(d,{when:L,children:t=>(()=>{var n=W(),r=n.firstChild,l=r.firstChild;return n.$$click=()=>e.onLoadEntries(t()),v(()=>c(l,"title",t())),n})()}),i(d,{get when(){return e.browserLoading()&&h===null},get children(){var t=N();return s(t,()=>e.t("instanceInfo.loading")),t}}),i(F,{each:P,children:t=>(()=>{var n=H(),r=n.firstChild,l=r.firstChild,a=l.firstChild,f=l.nextSibling,E=f.firstChild;return n.$$click=()=>{if(t.type==="directory"){e.onLoadEntries(t.path);return}e.onRequestOpenFile(t.path)},s(a,()=>t.name),s(E,()=>t.type),v(u=>{var b=`file-list-item ${e.browserSelectedPath()===t.path?"file-list-item-active":""}`,S=t.path,$=t.path;return b!==u.e&&z(n,u.e=b),S!==u.t&&c(n,"title",u.t=S),$!==u.a&&c(l,"title",u.a=$),u},{e:void 0,t:void 0,a:void 0}),n})()})];return i(T,{get header(){return[(()=>{var t=B(),n=t.firstChild,r=n.firstChild,l=r.firstChild;return s(l,w),s(t,i(d,{get when(){return e.browserLoading()},get children(){var a=j();return s(a,()=>e.t("instanceInfo.loading")),a}}),null),s(t,i(d,{get when(){return e.browserError()},children:a=>(()=>{var f=Q();return s(f,a),f})()}),null),v(()=>c(r,"title",w())),t})(),(()=>{var t=G();return t.$$click=C,s(t,i(d,{get when(){return e.browserSelectedSaving()},get fallback(){return i(q,{class:"h-4 w-4"})},get children(){return i(y,{class:"h-4 w-4 animate-spin"})}})),v(n=>{var r=e.t("instanceShell.rightPanel.actions.save")||"Save (Ctrl+S)",l=e.t("instanceShell.rightPanel.actions.save")||"Save",a=e.browserSelectedSaving()||!e.browserSelectedDirty();return r!==n.e&&c(t,"title",n.e=r),l!==n.t&&c(t,"aria-label",n.t=l),a!==n.a&&(t.disabled=n.a=a),n},{e:void 0,t:void 0,a:void 0}),t})(),(()=>{var t=J();return t.$$click=()=>e.onRefresh(),s(t,i(y,{get class(){return`h-4 w-4${e.browserLoading()?" animate-spin":""}`}})),v(n=>{var r=e.t("instanceShell.rightPanel.actions.refresh"),l=e.t("instanceShell.rightPanel.actions.refresh"),a=e.browserLoading();return r!==n.e&&c(t,"title",n.e=r),l!==n.t&&c(t,"aria-label",n.t=l),a!==n.a&&(t.disabled=n.a=a),n},{e:void 0,t:void 0,a:void 0}),t})()]},list:{panel:m,overlay:m},get viewer(){return k()},get listOpen(){return e.listOpen()},get onToggleList(){return e.onToggleList},get splitWidth(){return e.splitWidth()},get onResizeMouseDown(){return e.onResizeMouseDown},get onResizeTouchStart(){return e.onResizeTouchStart},get isPhoneLayout(){return e.isPhoneLayout()},get overlayAriaLabel(){return e.t("instanceShell.rightPanel.tabs.files")}})})};I(["click"]);export{ae as default};
|