offsite 0.0.32 → 0.0.33
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/apps/server/dist/main.mjs +102 -11
- package/apps/server/dist/main.mjs.map +1 -1
- package/apps/web/dist/assets/{dist-Dce5gUb9.js → dist-BrbsojdV.js} +1 -1
- package/apps/web/dist/assets/index-CwgEGzdv.css +2 -0
- package/apps/web/dist/assets/index-Dey2-CSd.js +782 -0
- package/apps/web/dist/index.html +2 -2
- package/apps/web/dist/sw.js +1 -1
- package/package.json +1 -1
- package/apps/web/dist/assets/index-BNP3kNP8.css +0 -2
- package/apps/web/dist/assets/index-D1dHWaOx.js +0 -782
|
@@ -24,6 +24,7 @@ import { integer, snakeCase, text } from "drizzle-orm/sqlite-core";
|
|
|
24
24
|
import { promisify } from "node:util";
|
|
25
25
|
import webPush from "web-push";
|
|
26
26
|
import { createProxyServer } from "http-proxy-3";
|
|
27
|
+
import { OUTGOING_PASSES } from "http-proxy-3/dist/lib/http-proxy/passes/web-outgoing.js";
|
|
27
28
|
import { spawn as spawn$1 } from "@lydell/node-pty";
|
|
28
29
|
//#region ../core/src/media.ts
|
|
29
30
|
const mediaTypes = /* @__PURE__ */ new Map([
|
|
@@ -890,6 +891,7 @@ function accountSchema(provider) {
|
|
|
890
891
|
id: z.string(),
|
|
891
892
|
provider: z.literal(provider),
|
|
892
893
|
name: z.string(),
|
|
894
|
+
color: z.string().regex(/^#[0-9a-f]{6}$/i, "must be a hex color like #3b82f6").nullable().default(null),
|
|
893
895
|
configDir: platformDirs,
|
|
894
896
|
enabled: z.boolean().default(true),
|
|
895
897
|
hiddenModels: z.record(z.string(), z.boolean()).default({})
|
|
@@ -3458,6 +3460,14 @@ function openCodeRuns() {
|
|
|
3458
3460
|
}
|
|
3459
3461
|
//#endregion
|
|
3460
3462
|
//#region src/services/accounts.ts
|
|
3463
|
+
const accountColors = [
|
|
3464
|
+
"#3b82f6",
|
|
3465
|
+
"#16a34a",
|
|
3466
|
+
"#f97316",
|
|
3467
|
+
"#a855f7",
|
|
3468
|
+
"#ec4899",
|
|
3469
|
+
"#0d9488"
|
|
3470
|
+
];
|
|
3461
3471
|
const providerNames = {
|
|
3462
3472
|
claude: "Claude",
|
|
3463
3473
|
codex: "Codex",
|
|
@@ -3468,13 +3478,11 @@ function providerName(provider) {
|
|
|
3468
3478
|
}
|
|
3469
3479
|
function storedAccounts() {
|
|
3470
3480
|
const config = readConfig();
|
|
3471
|
-
return [...config.claudeAccounts.map((item) => ({
|
|
3472
|
-
...item,
|
|
3473
|
-
configDir: item.configDir[platform()]
|
|
3474
|
-
})), ...config.codexAccounts.map((item) => ({
|
|
3481
|
+
return [...config.claudeAccounts, ...config.codexAccounts].map((item, index) => ({
|
|
3475
3482
|
...item,
|
|
3483
|
+
color: item.color ?? accountColors[index % accountColors.length],
|
|
3476
3484
|
configDir: item.configDir[platform()]
|
|
3477
|
-
}))
|
|
3485
|
+
}));
|
|
3478
3486
|
}
|
|
3479
3487
|
function assertEnabled(provider, accountId) {
|
|
3480
3488
|
if (!readConfig().enabledProviders[provider]) throw new Error(`${providerName(provider)} is disabled in Settings`);
|
|
@@ -3576,6 +3584,8 @@ function providerCapabilities(provider, accountId, cwd) {
|
|
|
3576
3584
|
}
|
|
3577
3585
|
function addAccount(provider, name, configDir) {
|
|
3578
3586
|
const account = validAccount(name, configDir);
|
|
3587
|
+
const stored = storedAccounts();
|
|
3588
|
+
const color = accountColors.find((item) => stored.every((other) => other.color !== item)) ?? accountColors[stored.length % accountColors.length];
|
|
3579
3589
|
const config = readConfig();
|
|
3580
3590
|
const key = `${provider}Accounts`;
|
|
3581
3591
|
saveConfig({
|
|
@@ -3584,6 +3594,7 @@ function addAccount(provider, name, configDir) {
|
|
|
3584
3594
|
id: randomUUID(),
|
|
3585
3595
|
provider,
|
|
3586
3596
|
name: account.name,
|
|
3597
|
+
color,
|
|
3587
3598
|
configDir: { [platform()]: account.configDir },
|
|
3588
3599
|
enabled: true,
|
|
3589
3600
|
hiddenModels: {}
|
|
@@ -3601,6 +3612,7 @@ async function updateAccount(update) {
|
|
|
3601
3612
|
[key]: config[key].map((item) => item.id === update.id ? {
|
|
3602
3613
|
...item,
|
|
3603
3614
|
name: account.name,
|
|
3615
|
+
color: update.color,
|
|
3604
3616
|
configDir: {
|
|
3605
3617
|
...item.configDir,
|
|
3606
3618
|
[platform()]: account.configDir
|
|
@@ -5094,6 +5106,46 @@ function resolveProjectFile(cwd, file) {
|
|
|
5094
5106
|
//#endregion
|
|
5095
5107
|
//#region src/services/proxy.ts
|
|
5096
5108
|
const proxies = /* @__PURE__ */ new Map();
|
|
5109
|
+
const pageScriptPath = "/__offsite/browser.js";
|
|
5110
|
+
function pageScript(origin) {
|
|
5111
|
+
return `(() => {
|
|
5112
|
+
if (window.parent === window || window.navigation === undefined) {
|
|
5113
|
+
return
|
|
5114
|
+
}
|
|
5115
|
+
const post = (message) =>
|
|
5116
|
+
window.parent.postMessage({ offsite: 'browser', ...message }, '*')
|
|
5117
|
+
const report = () =>
|
|
5118
|
+
post({
|
|
5119
|
+
event: 'location',
|
|
5120
|
+
url: ${JSON.stringify(origin)} + location.pathname + location.search + location.hash,
|
|
5121
|
+
proxied: location.href,
|
|
5122
|
+
back: navigation.canGoBack,
|
|
5123
|
+
forward: navigation.canGoForward,
|
|
5124
|
+
})
|
|
5125
|
+
addEventListener('pageshow', report)
|
|
5126
|
+
navigation.addEventListener('currententrychange', report)
|
|
5127
|
+
navigation.addEventListener('navigate', (event) => {
|
|
5128
|
+
if (!event.destination.sameDocument && event.downloadRequest === null) {
|
|
5129
|
+
post({ event: 'navigate' })
|
|
5130
|
+
}
|
|
5131
|
+
})
|
|
5132
|
+
addEventListener('message', (event) => {
|
|
5133
|
+
if (event.source !== window.parent || event.data?.offsite !== 'browser') {
|
|
5134
|
+
return
|
|
5135
|
+
}
|
|
5136
|
+
if (event.data.command === 'back') {
|
|
5137
|
+
navigation.back()
|
|
5138
|
+
}
|
|
5139
|
+
if (event.data.command === 'forward') {
|
|
5140
|
+
navigation.forward()
|
|
5141
|
+
}
|
|
5142
|
+
if (event.data.command === 'reload') {
|
|
5143
|
+
location.reload()
|
|
5144
|
+
}
|
|
5145
|
+
})
|
|
5146
|
+
})()
|
|
5147
|
+
`;
|
|
5148
|
+
}
|
|
5097
5149
|
function proxyPort(origin) {
|
|
5098
5150
|
const target = new URL(origin);
|
|
5099
5151
|
if (target.protocol !== "http:" && target.protocol !== "https:") throw new Error(`${origin} is not an http or https address`);
|
|
@@ -5105,21 +5157,43 @@ function proxyPort(origin) {
|
|
|
5105
5157
|
return started;
|
|
5106
5158
|
}
|
|
5107
5159
|
function startProxy(target) {
|
|
5108
|
-
const
|
|
5109
|
-
target
|
|
5160
|
+
const options = {
|
|
5161
|
+
target,
|
|
5110
5162
|
changeOrigin: true,
|
|
5111
5163
|
ws: true,
|
|
5112
5164
|
secure: false,
|
|
5113
5165
|
autoRewrite: true,
|
|
5114
5166
|
protocolRewrite: "http",
|
|
5115
|
-
cookieDomainRewrite: ""
|
|
5167
|
+
cookieDomainRewrite: "",
|
|
5168
|
+
selfHandleResponse: true
|
|
5169
|
+
};
|
|
5170
|
+
const proxy = createProxyServer(options);
|
|
5171
|
+
proxy.on("proxyReq", (outgoing, request) => {
|
|
5172
|
+
rewriteOrigin(target, outgoing, request);
|
|
5173
|
+
if (request.headers.accept?.startsWith("text/html") === true) outgoing.removeHeader("accept-encoding");
|
|
5116
5174
|
});
|
|
5117
|
-
proxy.on("proxyReq", (outgoing, request) => rewriteOrigin(target, outgoing, request));
|
|
5118
5175
|
proxy.on("proxyReqWs", (outgoing, request) => rewriteOrigin(target, outgoing, request));
|
|
5119
|
-
proxy.on("proxyRes", (incoming) => {
|
|
5176
|
+
proxy.on("proxyRes", async (incoming, request, response) => {
|
|
5177
|
+
try {
|
|
5178
|
+
await rewriteRedirect(target, incoming, request);
|
|
5179
|
+
} catch (error) {
|
|
5180
|
+
response.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
|
|
5181
|
+
response.end(`Could not follow the redirect from ${target.origin}: ${error instanceof Error ? error.message : String(error)}`);
|
|
5182
|
+
return;
|
|
5183
|
+
}
|
|
5120
5184
|
delete incoming.headers["x-frame-options"];
|
|
5121
5185
|
delete incoming.headers["content-security-policy"];
|
|
5122
5186
|
if (incoming.headers["set-cookie"] !== void 0) incoming.headers["set-cookie"] = incoming.headers["set-cookie"].map((cookie) => cookie.replace(/;\s*secure/i, "").replace(/;\s*samesite=none/i, ""));
|
|
5187
|
+
const page = request.method === "GET" && request.headers.accept?.startsWith("text/html") === true && incoming.statusCode !== 204 && incoming.statusCode !== 304 && /^text\/html/i.test(incoming.headers["content-type"] ?? "") && incoming.headers["content-encoding"] === void 0;
|
|
5188
|
+
if (page) delete incoming.headers["content-length"];
|
|
5189
|
+
for (const pass of Object.values(OUTGOING_PASSES)) pass(request, response, incoming, options);
|
|
5190
|
+
if (!page) {
|
|
5191
|
+
incoming.pipe(response);
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
const chunks = [];
|
|
5195
|
+
incoming.on("data", (chunk) => chunks.push(chunk));
|
|
5196
|
+
incoming.on("end", () => response.end(Buffer.from(Buffer.concat(chunks).toString("latin1").replace(/^(\xEF\xBB\xBF)?\s*(<!doctype[^>]*>)?/i, `$&<script src="${pageScriptPath}"><\/script>`), "latin1")));
|
|
5123
5197
|
});
|
|
5124
5198
|
proxy.on("error", (error, _request, response) => {
|
|
5125
5199
|
if (!(response instanceof http.ServerResponse)) {
|
|
@@ -5129,7 +5203,14 @@ function startProxy(target) {
|
|
|
5129
5203
|
if (!response.headersSent) response.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
|
|
5130
5204
|
response.end(`Could not reach ${target.origin}: ${error.message}`);
|
|
5131
5205
|
});
|
|
5132
|
-
const server = http.createServer((request, response) =>
|
|
5206
|
+
const server = http.createServer((request, response) => {
|
|
5207
|
+
if (request.url === pageScriptPath) {
|
|
5208
|
+
response.writeHead(200, { "content-type": "text/javascript; charset=utf-8" });
|
|
5209
|
+
response.end(pageScript(target.origin));
|
|
5210
|
+
return;
|
|
5211
|
+
}
|
|
5212
|
+
proxy.web(request, response);
|
|
5213
|
+
});
|
|
5133
5214
|
server.on("upgrade", (request, socket, head) => proxy.ws(request, socket, head));
|
|
5134
5215
|
return new Promise((resolve, reject) => {
|
|
5135
5216
|
server.once("error", reject);
|
|
@@ -5143,6 +5224,16 @@ function startProxy(target) {
|
|
|
5143
5224
|
});
|
|
5144
5225
|
});
|
|
5145
5226
|
}
|
|
5227
|
+
async function rewriteRedirect(target, incoming, request) {
|
|
5228
|
+
const location = incoming.headers.location;
|
|
5229
|
+
if (location === void 0 || !/^30[1278]$/.test(String(incoming.statusCode))) return;
|
|
5230
|
+
const next = new URL(location, target);
|
|
5231
|
+
if (next.origin === target.origin || next.protocol !== "http:" && next.protocol !== "https:") return;
|
|
5232
|
+
if (request.headers.host === void 0) throw new Error("the redirected request has no host");
|
|
5233
|
+
const proxied = new URL(`http://${request.headers.host}`);
|
|
5234
|
+
proxied.port = String(await proxyPort(next.origin));
|
|
5235
|
+
incoming.headers.location = `${proxied.origin}${next.pathname}${next.search}${next.hash}`;
|
|
5236
|
+
}
|
|
5146
5237
|
function rewriteOrigin(target, outgoing, request) {
|
|
5147
5238
|
if (request.headers.origin !== void 0) outgoing.setHeader("origin", target.origin);
|
|
5148
5239
|
if (request.headers.referer !== void 0) outgoing.setHeader("referer", request.headers.referer.replace(`http://${request.headers.host}`, target.origin));
|