@maintainer-pro/ai-bridge 0.1.20 → 0.1.22
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/package.json +2 -2
- package/src/daemon.mjs +57 -50
- package/src/share-rewrite.mjs +180 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maintainer-pro/ai-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"description": "Local bridge daemon that pairs a machine to Maintainer Pro and configures multiple client sandboxes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"maintainer-pro",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"node": ">=22"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@maintainer-pro/ai-cli": "^0.1.
|
|
31
|
+
"@maintainer-pro/ai-cli": "^0.1.12",
|
|
32
32
|
"@maintainer-pro/ai-server": "^0.1.7"
|
|
33
33
|
}
|
|
34
34
|
}
|
package/src/daemon.mjs
CHANGED
|
@@ -257,7 +257,21 @@ function loadConfig() {
|
|
|
257
257
|
const file = configPath();
|
|
258
258
|
if (!fs.existsSync(file)) return null;
|
|
259
259
|
try {
|
|
260
|
-
|
|
260
|
+
const cfg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
261
|
+
let dirty = false;
|
|
262
|
+
for (const ws of cfg.workspaces || []) {
|
|
263
|
+
const before = JSON.stringify(ws.hostApps || []);
|
|
264
|
+
const beforeProxy = JSON.stringify(ws.proxy || null);
|
|
265
|
+
stripAiServerFromWorkspace(ws);
|
|
266
|
+
if (
|
|
267
|
+
JSON.stringify(ws.hostApps || []) !== before ||
|
|
268
|
+
JSON.stringify(ws.proxy || null) !== beforeProxy
|
|
269
|
+
) {
|
|
270
|
+
dirty = true;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (dirty) saveConfig(cfg);
|
|
274
|
+
return cfg;
|
|
261
275
|
} catch {
|
|
262
276
|
return null;
|
|
263
277
|
}
|
|
@@ -434,7 +448,7 @@ async function resolveWorkspaceHostApps(ws, opts = {}) {
|
|
|
434
448
|
const match = previous.find((row) => row && row.id === app.id);
|
|
435
449
|
return match ? { ...app, host: match.host === true || app.host === true } : app;
|
|
436
450
|
});
|
|
437
|
-
ws.hostApps = result.apps;
|
|
451
|
+
ws.hostApps = listedHostApps(result.apps);
|
|
438
452
|
if (opts.cfg) persistWorkspaceEntry(opts.cfg, ws);
|
|
439
453
|
const summary = result.apps
|
|
440
454
|
.map((app) => `${app.name}:${app.port}`)
|
|
@@ -455,19 +469,10 @@ async function resolveWorkspaceHostApps(ws, opts = {}) {
|
|
|
455
469
|
activity(
|
|
456
470
|
ws.sandboxId,
|
|
457
471
|
"warn",
|
|
458
|
-
`port detect failed (${message}) —
|
|
472
|
+
`port detect failed (${message}) — no host apps listed yet`
|
|
459
473
|
);
|
|
460
474
|
if (!Array.isArray(ws.hostApps) || !ws.hostApps.length) {
|
|
461
|
-
ws.hostApps = [
|
|
462
|
-
{
|
|
463
|
-
id: "ai-server",
|
|
464
|
-
name: "AI server",
|
|
465
|
-
role: "ai-server",
|
|
466
|
-
port: Number(ws.port) || 3100,
|
|
467
|
-
source: "default",
|
|
468
|
-
locked: true,
|
|
469
|
-
},
|
|
470
|
-
];
|
|
475
|
+
ws.hostApps = [];
|
|
471
476
|
}
|
|
472
477
|
return {
|
|
473
478
|
apps: ws.hostApps,
|
|
@@ -763,8 +768,31 @@ function isLocalAppUrl(url) {
|
|
|
763
768
|
}
|
|
764
769
|
}
|
|
765
770
|
|
|
771
|
+
function isAiServerApp(app) {
|
|
772
|
+
return Boolean(app && (app.role === "ai-server" || app.id === "ai-server"));
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
function listedHostApps(apps) {
|
|
776
|
+
return (Array.isArray(apps) ? apps : []).filter((app) => !isAiServerApp(app));
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
function stripAiServerFromWorkspace(ws) {
|
|
780
|
+
if (!ws || typeof ws !== "object") return ws;
|
|
781
|
+
if (Array.isArray(ws.hostApps)) ws.hostApps = listedHostApps(ws.hostApps);
|
|
782
|
+
if (ws.proxy && typeof ws.proxy === "object") {
|
|
783
|
+
if (ws.proxy.slugs && typeof ws.proxy.slugs === "object") {
|
|
784
|
+
delete ws.proxy.slugs["ai-server"];
|
|
785
|
+
}
|
|
786
|
+
if (ws.proxy.urls && typeof ws.proxy.urls === "object") {
|
|
787
|
+
delete ws.proxy.urls["ai-server"];
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return ws;
|
|
791
|
+
}
|
|
792
|
+
|
|
766
793
|
function persistWorkspaceEntry(cfg, ws) {
|
|
767
794
|
if (!cfg || !ws?.sandboxId) return;
|
|
795
|
+
stripAiServerFromWorkspace(ws);
|
|
768
796
|
cfg.workspaces = cfg.workspaces || [];
|
|
769
797
|
const index = cfg.workspaces.findIndex((row) => row.sandboxId === ws.sandboxId);
|
|
770
798
|
if (index >= 0) cfg.workspaces[index] = { ...cfg.workspaces[index], ...ws };
|
|
@@ -1001,16 +1029,7 @@ function probeEmbedConfig(url, timeoutMs = 2500) {
|
|
|
1001
1029
|
|
|
1002
1030
|
function sanitizeAiServerPort(ws) {
|
|
1003
1031
|
if (!ws || typeof ws !== "object") return;
|
|
1004
|
-
|
|
1005
|
-
for (const app of apps) {
|
|
1006
|
-
if (
|
|
1007
|
-
app &&
|
|
1008
|
-
(app.role === "ai-server" || app.id === "ai-server") &&
|
|
1009
|
-
isAdminListenPort(app.port)
|
|
1010
|
-
) {
|
|
1011
|
-
app.port = 3100;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1032
|
+
if (Array.isArray(ws.hostApps)) ws.hostApps = listedHostApps(ws.hostApps);
|
|
1014
1033
|
if (isAdminListenPort(ws.port)) ws.port = 3100;
|
|
1015
1034
|
}
|
|
1016
1035
|
|
|
@@ -1304,10 +1323,6 @@ async function reconcileWorkspacePresence(ws, cfg, opts = {}) {
|
|
|
1304
1323
|
// 3. Host + CORS origins for Maintainer Pro
|
|
1305
1324
|
const host = workspaceHostReport(ws);
|
|
1306
1325
|
const uiShare = proxyUrlForApp(ws, hostAppOf(ws) || { id: "ui", role: "ui", host: true });
|
|
1307
|
-
const aiShare = proxyUrlForApp(ws, {
|
|
1308
|
-
id: "ai-server",
|
|
1309
|
-
role: "ai-server",
|
|
1310
|
-
});
|
|
1311
1326
|
if (uiShare) {
|
|
1312
1327
|
host.appUrl = uiShare;
|
|
1313
1328
|
} else if (probe.running) {
|
|
@@ -1316,12 +1331,9 @@ async function reconcileWorkspacePresence(ws, cfg, opts = {}) {
|
|
|
1316
1331
|
);
|
|
1317
1332
|
if (ui?.port) {
|
|
1318
1333
|
host.appUrl = `http://localhost:${ui.port}`;
|
|
1319
|
-
} else if (probe.chatUp) {
|
|
1320
|
-
host.appUrl = `http://localhost:${probe.chatPort}`;
|
|
1321
1334
|
}
|
|
1322
1335
|
}
|
|
1323
1336
|
if (uiShare && !host.origins.includes(uiShare)) host.origins.push(uiShare);
|
|
1324
|
-
if (aiShare && !host.origins.includes(aiShare)) host.origins.push(aiShare);
|
|
1325
1337
|
const proxyOrigin = String(ws?.proxy?.origin || "").replace(/\/$/, "");
|
|
1326
1338
|
if (proxyOrigin && !host.origins.includes(proxyOrigin)) {
|
|
1327
1339
|
host.origins.push(proxyOrigin);
|
|
@@ -1491,7 +1503,7 @@ function uniqueProxySlugs(apps) {
|
|
|
1491
1503
|
const used = new Set();
|
|
1492
1504
|
/** @type {Record<string, string>} */
|
|
1493
1505
|
const slugs = {};
|
|
1494
|
-
for (const app of apps
|
|
1506
|
+
for (const app of listedHostApps(apps)) {
|
|
1495
1507
|
let slug = proxySlugForApp(app);
|
|
1496
1508
|
if (!slug || !app?.id) continue;
|
|
1497
1509
|
if (used.has(slug)) {
|
|
@@ -1512,7 +1524,7 @@ function uniqueProxySlugs(apps) {
|
|
|
1512
1524
|
}
|
|
1513
1525
|
|
|
1514
1526
|
function sharePortUrls(ws) {
|
|
1515
|
-
const apps =
|
|
1527
|
+
const apps = listedHostApps(ws?.hostApps);
|
|
1516
1528
|
/** @type {Record<string, string>} */
|
|
1517
1529
|
const out = {};
|
|
1518
1530
|
for (const app of apps) {
|
|
@@ -1547,8 +1559,10 @@ function applyAssignedProxy(ws, remote, cfg) {
|
|
|
1547
1559
|
}
|
|
1548
1560
|
|
|
1549
1561
|
function appsFrom(ws, remote) {
|
|
1550
|
-
if (Array.isArray(ws?.hostApps) && ws.hostApps.length)
|
|
1551
|
-
|
|
1562
|
+
if (Array.isArray(ws?.hostApps) && ws.hostApps.length) {
|
|
1563
|
+
return listedHostApps(ws.hostApps);
|
|
1564
|
+
}
|
|
1565
|
+
if (Array.isArray(remote?.hostApps)) return listedHostApps(remote.hostApps);
|
|
1552
1566
|
return [];
|
|
1553
1567
|
}
|
|
1554
1568
|
|
|
@@ -1569,10 +1583,9 @@ function proxyUrlForApp(ws, app) {
|
|
|
1569
1583
|
}
|
|
1570
1584
|
|
|
1571
1585
|
function jobsFromHostApps(ws, filter = {}) {
|
|
1572
|
-
const apps =
|
|
1586
|
+
const apps = listedHostApps(ws.hostApps);
|
|
1573
1587
|
const hostId = hostAppOf(ws)?.id;
|
|
1574
1588
|
return apps
|
|
1575
|
-
.filter((app) => app && app.role !== "ai-server")
|
|
1576
1589
|
.filter((app) => (filter.appId ? app.id === filter.appId : true))
|
|
1577
1590
|
.map((app) => {
|
|
1578
1591
|
const port = Number(app.port) || 3000;
|
|
@@ -1622,7 +1635,7 @@ async function probeRunningApps(ws, timeoutMs = 2500) {
|
|
|
1622
1635
|
appId: job.appId || job.role,
|
|
1623
1636
|
});
|
|
1624
1637
|
}
|
|
1625
|
-
const listed =
|
|
1638
|
+
const listed = listedHostApps(ws.hostApps);
|
|
1626
1639
|
const hostApps = await Promise.all(
|
|
1627
1640
|
listed.map(async (app) => {
|
|
1628
1641
|
const port = Number(app.port) || 0;
|
|
@@ -1645,7 +1658,7 @@ async function probeRunningApps(ws, timeoutMs = 2500) {
|
|
|
1645
1658
|
chatPort: chat.port,
|
|
1646
1659
|
hosts,
|
|
1647
1660
|
hostApps,
|
|
1648
|
-
running:
|
|
1661
|
+
running: hosts.some((host) => host.up) || hostApps.some((app) => app.running),
|
|
1649
1662
|
};
|
|
1650
1663
|
}
|
|
1651
1664
|
|
|
@@ -1662,9 +1675,7 @@ async function restoreHostsAfterReconnect(cfg) {
|
|
|
1662
1675
|
.join(" ");
|
|
1663
1676
|
if (status.appsRunning) {
|
|
1664
1677
|
log(
|
|
1665
|
-
`found running apps for ${label}:
|
|
1666
|
-
status.probe.chatUp ? "(up)" : "(down)"
|
|
1667
|
-
}${hostSummary ? ` ${hostSummary}` : ""} share=${
|
|
1678
|
+
`found running apps for ${label}: ${hostSummary || "(none)"} share=${
|
|
1668
1679
|
status.host.appUrl || "(none)"
|
|
1669
1680
|
} origins=${
|
|
1670
1681
|
status.host.origins.join(",") || "none"
|
|
@@ -1703,10 +1714,7 @@ async function prepareWorkspaceLaunch(ws, cfg, reserved) {
|
|
|
1703
1714
|
return { aiPort, jobs: [] };
|
|
1704
1715
|
}
|
|
1705
1716
|
log(`ports pick ${label} in ${folder}`);
|
|
1706
|
-
const
|
|
1707
|
-
? ws.hostApps.find((app) => app.role === "ai-server" || app.id === "ai-server")
|
|
1708
|
-
: null;
|
|
1709
|
-
const preferredRaw = Number(listedAi?.port || ws.port) || 3100;
|
|
1717
|
+
const preferredRaw = Number(ws.port) || 3100;
|
|
1710
1718
|
const preferredAi = isAdminListenPort(preferredRaw) ? 3100 : preferredRaw;
|
|
1711
1719
|
const aiUp = await isChatServerOnPort(preferredAi);
|
|
1712
1720
|
const aiPort = aiUp
|
|
@@ -4679,12 +4687,11 @@ async function runActions(cfg, actions) {
|
|
|
4679
4687
|
String(action.payload.folderPathRemaining || remaining[0] || ws.folderPath);
|
|
4680
4688
|
ws.folderPath = primary;
|
|
4681
4689
|
ws.extraFolders = remaining.filter((folder) => !sameFolder(folder, primary));
|
|
4682
|
-
ws.hostApps = (
|
|
4690
|
+
ws.hostApps = listedHostApps(
|
|
4691
|
+
Array.isArray(ws.hostApps) ? ws.hostApps : []
|
|
4692
|
+
).filter(
|
|
4683
4693
|
(app) =>
|
|
4684
|
-
!app ||
|
|
4685
|
-
app.role === "ai-server" ||
|
|
4686
|
-
!app.folderPath ||
|
|
4687
|
-
!sameFolder(app.folderPath, removed)
|
|
4694
|
+
!app.folderPath || !sameFolder(app.folderPath, removed)
|
|
4688
4695
|
);
|
|
4689
4696
|
persistWorkspaceEntry(cfg, ws);
|
|
4690
4697
|
result = {
|
package/src/share-rewrite.mjs
CHANGED
|
@@ -274,6 +274,33 @@ function mappedUrlForPort(portUrls, port) {
|
|
|
274
274
|
return dest ? String(dest).replace(/\/$/, "") : "";
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
function backendShareBase(portUrls) {
|
|
278
|
+
if (!portUrls || typeof portUrls !== "object") return "";
|
|
279
|
+
for (const dest of Object.values(portUrls)) {
|
|
280
|
+
const url = String(dest || "").replace(/\/$/, "");
|
|
281
|
+
if (!url) continue;
|
|
282
|
+
try {
|
|
283
|
+
const slug = new URL(url).pathname.split("/").filter(Boolean)[2] || "";
|
|
284
|
+
if (slug === "backend" || slug.startsWith("backend-")) return url;
|
|
285
|
+
} catch {
|
|
286
|
+
if (/\/backend(?:-[^/]+)?$/i.test(url)) return url;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return "";
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function shareBaseForPath(path, publicBase, portUrls) {
|
|
293
|
+
const pathname = String(path || "").split("?")[0] || "/";
|
|
294
|
+
if (
|
|
295
|
+
isShareAssetPath(pathname) ||
|
|
296
|
+
pathname.startsWith("/_next/") ||
|
|
297
|
+
pathname.startsWith("/@")
|
|
298
|
+
) {
|
|
299
|
+
return publicBase;
|
|
300
|
+
}
|
|
301
|
+
return backendShareBase(portUrls) || publicBase;
|
|
302
|
+
}
|
|
303
|
+
|
|
277
304
|
function isProbablyUtf8Text(buf) {
|
|
278
305
|
if (!Buffer.isBuffer(buf) || !buf.length || buf.length > 8 * 1024 * 1024) {
|
|
279
306
|
return false;
|
|
@@ -347,7 +374,7 @@ export function rewriteMappedLocalUrls(text, portUrls) {
|
|
|
347
374
|
* @param {Record<string, string>} headers
|
|
348
375
|
* @param {Record<string, string> | null | undefined} portUrls
|
|
349
376
|
*/
|
|
350
|
-
export function rewriteShareRequestBody(body, headers, portUrls,
|
|
377
|
+
export function rewriteShareRequestBody(body, headers, portUrls, _publicBase) {
|
|
351
378
|
if (!body) return body;
|
|
352
379
|
const buf = Buffer.isBuffer(body) ? body : Buffer.from(body);
|
|
353
380
|
if (!buf.length) return buf;
|
|
@@ -357,7 +384,6 @@ export function rewriteShareRequestBody(body, headers, portUrls, publicBase) {
|
|
|
357
384
|
if (portUrls && Object.keys(portUrls).length) {
|
|
358
385
|
next = rewriteMappedLocalUrls(next, portUrls);
|
|
359
386
|
}
|
|
360
|
-
if (publicBase) next = rewriteShareOriginPaths(next, publicBase);
|
|
361
387
|
if (next === text) return buf;
|
|
362
388
|
return Buffer.from(next, "utf8");
|
|
363
389
|
}
|
|
@@ -411,7 +437,7 @@ function rewriteHeaderUrls(headers, publicBase, port, portUrls) {
|
|
|
411
437
|
if (lower === "set-cookie" || lower === "content-length" || lower === "content-encoding") {
|
|
412
438
|
continue;
|
|
413
439
|
}
|
|
414
|
-
headers[key] = rewriteShareOriginPaths(headers[key], publicBase);
|
|
440
|
+
headers[key] = rewriteShareOriginPaths(headers[key], publicBase, portUrls);
|
|
415
441
|
}
|
|
416
442
|
}
|
|
417
443
|
}
|
|
@@ -449,7 +475,7 @@ export function prefixShareOriginUrl(value, publicBase) {
|
|
|
449
475
|
}
|
|
450
476
|
}
|
|
451
477
|
|
|
452
|
-
export function rewriteShareOriginPaths(text, publicBase) {
|
|
478
|
+
export function rewriteShareOriginPaths(text, publicBase, portUrls) {
|
|
453
479
|
if (!text || !publicBase) return text;
|
|
454
480
|
let origin = "";
|
|
455
481
|
try {
|
|
@@ -462,15 +488,24 @@ export function rewriteShareOriginPaths(text, publicBase) {
|
|
|
462
488
|
const originSlashEsc = origin
|
|
463
489
|
.replace(/\//g, "\\/")
|
|
464
490
|
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
491
|
+
const baseFor = function (matched) {
|
|
492
|
+
let path = "/";
|
|
493
|
+
try {
|
|
494
|
+
path = new URL(matched).pathname || "/";
|
|
495
|
+
} catch {
|
|
496
|
+
/* keep */
|
|
497
|
+
}
|
|
498
|
+
return shareBaseForPath(path, publicBase, portUrls);
|
|
499
|
+
};
|
|
465
500
|
let out = String(text);
|
|
466
501
|
out = out.replace(new RegExp(originEsc + "/(?!p/)[^\\s'\"<>\\\\]+", "gi"), function (matched) {
|
|
467
|
-
return prefixShareOriginUrl(matched,
|
|
502
|
+
return prefixShareOriginUrl(matched, baseFor(matched));
|
|
468
503
|
});
|
|
469
504
|
out = out.replace(
|
|
470
505
|
new RegExp(originSlashEsc + "\\\\/(?!p/)[^\\s'\"<>]+", "gi"),
|
|
471
506
|
function (matched) {
|
|
472
507
|
const unescaped = matched.replace(/\\\//g, "/");
|
|
473
|
-
return prefixShareOriginUrl(unescaped,
|
|
508
|
+
return prefixShareOriginUrl(unescaped, baseFor(unescaped)).replace(/\//g, "\\/");
|
|
474
509
|
}
|
|
475
510
|
);
|
|
476
511
|
return out;
|
|
@@ -496,7 +531,18 @@ function rewriteLocation(value, publicBase, port, portUrls) {
|
|
|
496
531
|
}
|
|
497
532
|
const fromPorts = rewriteMappedLocalUrls(String(value), portUrls);
|
|
498
533
|
if (fromPorts !== String(value)) return fromPorts;
|
|
499
|
-
if (publicBase)
|
|
534
|
+
if (publicBase) {
|
|
535
|
+
let path = "/";
|
|
536
|
+
try {
|
|
537
|
+
path = new URL(String(value)).pathname || "/";
|
|
538
|
+
} catch {
|
|
539
|
+
/* keep */
|
|
540
|
+
}
|
|
541
|
+
return prefixShareOriginUrl(
|
|
542
|
+
String(value),
|
|
543
|
+
shareBaseForPath(path, publicBase, portUrls)
|
|
544
|
+
);
|
|
545
|
+
}
|
|
500
546
|
} catch {
|
|
501
547
|
/* keep */
|
|
502
548
|
}
|
|
@@ -809,12 +855,11 @@ function prefixRootPaths(body, publicBase, contentType = "") {
|
|
|
809
855
|
let out = body;
|
|
810
856
|
if (
|
|
811
857
|
html &&
|
|
858
|
+
isViteDocument(out) &&
|
|
812
859
|
/<head[\s>]/i.test(out) &&
|
|
813
|
-
!/<base\s/i.test(out)
|
|
814
|
-
!isNextDocument(out)
|
|
860
|
+
!/<base\s/i.test(out)
|
|
815
861
|
) {
|
|
816
|
-
const
|
|
817
|
-
const href = joinProxyAndViteBase(pathPrefix, viteBase);
|
|
862
|
+
const href = joinProxyAndViteBase(pathPrefix, inferViteBase(out));
|
|
818
863
|
out = out.replace(/<head([^>]*)>/i, `<head$1><base href="${href}">`);
|
|
819
864
|
}
|
|
820
865
|
if (html) {
|
|
@@ -871,6 +916,12 @@ function isScriptRequestPath(path) {
|
|
|
871
916
|
return /\.(?:m?js|cjs)$/.test(p);
|
|
872
917
|
}
|
|
873
918
|
|
|
919
|
+
function isScriptOrJsonBody(headers, path) {
|
|
920
|
+
const mime = contentMime(headerGet(headers, "content-type"));
|
|
921
|
+
if (/javascript|ecmascript|json/.test(mime)) return true;
|
|
922
|
+
return isScriptRequestPath(path);
|
|
923
|
+
}
|
|
924
|
+
|
|
874
925
|
function rewriteLocalSidecarUrls(html, aiPublicBase, uiPublicBase) {
|
|
875
926
|
const ai = String(aiPublicBase || "").replace(/\/$/, "");
|
|
876
927
|
const ui = String(uiPublicBase || "").replace(/\/$/, "");
|
|
@@ -968,6 +1019,14 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
|
|
|
968
1019
|
)
|
|
969
1020
|
);
|
|
970
1021
|
}
|
|
1022
|
+
function loopback(h) {
|
|
1023
|
+
h = String(h || "")
|
|
1024
|
+
.replace(/^\[|\]$/g, "")
|
|
1025
|
+
.toLowerCase();
|
|
1026
|
+
return (
|
|
1027
|
+
h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "0.0.0.0"
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
971
1030
|
function prefixPath(path) {
|
|
972
1031
|
if (typeof path !== "string" || !path) return path;
|
|
973
1032
|
if (path.charAt(0) === "/" && path.charAt(1) !== "/") {
|
|
@@ -1005,12 +1064,29 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
|
|
|
1005
1064
|
} catch (e) {}
|
|
1006
1065
|
return v;
|
|
1007
1066
|
}
|
|
1067
|
+
function backendBase() {
|
|
1068
|
+
var map = portMap || {};
|
|
1069
|
+
var keys = Object.keys(map);
|
|
1070
|
+
for (var i = 0; i < keys.length; i++) {
|
|
1071
|
+
var url = String(map[keys[i]] || "").replace(/\/$/, "");
|
|
1072
|
+
if (!url) continue;
|
|
1073
|
+
try {
|
|
1074
|
+
var slug = new URL(url).pathname.split("/").filter(Boolean)[2] || "";
|
|
1075
|
+
if (slug === "backend" || slug.indexOf("backend-") === 0) return url;
|
|
1076
|
+
} catch (e) {
|
|
1077
|
+
if (/\/backend(?:-[^/]+)?$/i.test(url)) return url;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
return "";
|
|
1081
|
+
}
|
|
1008
1082
|
function addNav(v) {
|
|
1009
1083
|
if (typeof v !== "string" || !v) return v;
|
|
1010
|
-
|
|
1084
|
+
var mapped = mapLocal(v);
|
|
1085
|
+
if (mapped !== v) return mapped;
|
|
1011
1086
|
if (v.charAt(0) === "/" && v.charAt(1) !== "/") return prefixPath(v);
|
|
1012
1087
|
try {
|
|
1013
1088
|
var nav = new URL(v, location.href);
|
|
1089
|
+
if (!loopback(nav.hostname)) return v;
|
|
1014
1090
|
if (nav.origin !== location.origin) return v;
|
|
1015
1091
|
if (nav.pathname === "/" || nav.pathname === "") return v;
|
|
1016
1092
|
nav.pathname = prefixPath(nav.pathname);
|
|
@@ -1019,6 +1095,46 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
|
|
|
1019
1095
|
return v;
|
|
1020
1096
|
}
|
|
1021
1097
|
function addNet(v) {
|
|
1098
|
+
if (typeof v !== "string" || !v) return v;
|
|
1099
|
+
var mapped = mapLocal(v);
|
|
1100
|
+
if (mapped !== v) return mapped;
|
|
1101
|
+
var backend = backendBase();
|
|
1102
|
+
var path = "";
|
|
1103
|
+
var search = "";
|
|
1104
|
+
var hash = "";
|
|
1105
|
+
var abs = null;
|
|
1106
|
+
try {
|
|
1107
|
+
if (/^(https?:|wss?:)\/\//i.test(v)) {
|
|
1108
|
+
abs = new URL(v);
|
|
1109
|
+
var host = String(abs.hostname || "")
|
|
1110
|
+
.replace(/^\[|\]$/g, "")
|
|
1111
|
+
.toLowerCase();
|
|
1112
|
+
if (!loopback(host) && host !== String(location.hostname || "").toLowerCase()) {
|
|
1113
|
+
return v;
|
|
1114
|
+
}
|
|
1115
|
+
path = abs.pathname || "/";
|
|
1116
|
+
search = abs.search || "";
|
|
1117
|
+
hash = abs.hash || "";
|
|
1118
|
+
} else if (v.charAt(0) === "/" && v.charAt(1) !== "/") {
|
|
1119
|
+
var rel = new URL(v, location.href);
|
|
1120
|
+
path = rel.pathname || "/";
|
|
1121
|
+
search = rel.search || "";
|
|
1122
|
+
hash = rel.hash || "";
|
|
1123
|
+
} else {
|
|
1124
|
+
return addNav(v);
|
|
1125
|
+
}
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
return addNav(v);
|
|
1128
|
+
}
|
|
1129
|
+
if (path === "/api/v1" || path.indexOf("/api/v1/") === 0) return v;
|
|
1130
|
+
if (path.indexOf("/p/") === 0) return v;
|
|
1131
|
+
if (path === "/" || path === "") return addNav(v);
|
|
1132
|
+
if (isAsset(path)) return addNav(v);
|
|
1133
|
+
if (backend) {
|
|
1134
|
+
var dest = backend + path + search + hash;
|
|
1135
|
+
if (abs && /^ws/i.test(abs.protocol)) dest = dest.replace(/^http/i, "ws");
|
|
1136
|
+
return dest;
|
|
1137
|
+
}
|
|
1022
1138
|
return addNav(v);
|
|
1023
1139
|
}
|
|
1024
1140
|
function mapSel(sel) {
|
|
@@ -1213,13 +1329,62 @@ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
|
|
|
1213
1329
|
} catch (e) {}
|
|
1214
1330
|
return "";
|
|
1215
1331
|
}
|
|
1332
|
+
function loopback(h) {
|
|
1333
|
+
h = String(h || "")
|
|
1334
|
+
.replace(/^\[|\]$/g, "")
|
|
1335
|
+
.toLowerCase();
|
|
1336
|
+
return (
|
|
1337
|
+
h === "localhost" || h === "127.0.0.1" || h === "::1" || h === "0.0.0.0"
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
function backendBase() {
|
|
1341
|
+
var map = portMap || {};
|
|
1342
|
+
var keys = Object.keys(map);
|
|
1343
|
+
for (var i = 0; i < keys.length; i++) {
|
|
1344
|
+
var url = String(map[keys[i]] || "").replace(/\/$/, "");
|
|
1345
|
+
if (!url) continue;
|
|
1346
|
+
try {
|
|
1347
|
+
var slug = new URL(url).pathname.split("/").filter(Boolean)[2] || "";
|
|
1348
|
+
if (slug === "backend" || slug.indexOf("backend-") === 0) return url;
|
|
1349
|
+
} catch (e) {
|
|
1350
|
+
if (/\/backend(?:-[^/]+)?$/i.test(url)) return url;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return "";
|
|
1354
|
+
}
|
|
1216
1355
|
function prefixWith(url, prefix) {
|
|
1217
1356
|
if (!prefix) return url;
|
|
1218
1357
|
try {
|
|
1219
|
-
var
|
|
1358
|
+
var backend = backendBase();
|
|
1359
|
+
var parsed = new URL(url, self.location.href);
|
|
1360
|
+
var host = String(parsed.hostname || "")
|
|
1361
|
+
.replace(/^\[|\]$/g, "")
|
|
1362
|
+
.toLowerCase();
|
|
1363
|
+
var pageHost = String(self.location.hostname || "")
|
|
1364
|
+
.replace(/^\[|\]$/g, "")
|
|
1365
|
+
.toLowerCase();
|
|
1366
|
+
if (/^(https?:|wss?:)\/\//i.test(url) && !loopback(host) && host !== pageHost) {
|
|
1367
|
+
return url;
|
|
1368
|
+
}
|
|
1369
|
+
var path = parsed.pathname || "/";
|
|
1370
|
+
if (path === "/api/v1" || path.indexOf("/api/v1/") === 0) return url;
|
|
1371
|
+
if (path.indexOf("/p/") === 0) return url;
|
|
1372
|
+
if (
|
|
1373
|
+
backend &&
|
|
1374
|
+
path !== "/" &&
|
|
1375
|
+
path !== "" &&
|
|
1376
|
+
!/\/(?:_next\/|__nextjs_|@vite(?:\/|$)|@react-refresh(?:\/|$)|@fs\/|@id\/|node_modules\/)/.test(
|
|
1377
|
+
path
|
|
1378
|
+
) &&
|
|
1379
|
+
!/\.(?:m?[jt]sx?|cjs|mjs|css|scss|sass|less|map|wasm|vue|svelte)$/i.test(path)
|
|
1380
|
+
) {
|
|
1381
|
+
var dest = backend + path + (parsed.search || "") + (parsed.hash || "");
|
|
1382
|
+
if (/^ws/i.test(parsed.protocol)) dest = dest.replace(/^http/i, "ws");
|
|
1383
|
+
return dest;
|
|
1384
|
+
}
|
|
1385
|
+
var u = parsed;
|
|
1220
1386
|
if (u.origin !== self.location.origin) return url;
|
|
1221
1387
|
if (u.pathname === "/" || u.pathname === "") return url;
|
|
1222
|
-
if (u.pathname.indexOf("/p/") === 0) return url;
|
|
1223
1388
|
if (u.pathname === prefix || u.pathname.indexOf(prefix + "/") === 0) return url;
|
|
1224
1389
|
u.pathname = u.pathname === "/" ? prefix : prefix + u.pathname;
|
|
1225
1390
|
return u.toString();
|
|
@@ -1393,7 +1558,7 @@ export function processShareHttpResponse(opts) {
|
|
|
1393
1558
|
}
|
|
1394
1559
|
}
|
|
1395
1560
|
if (publicBase && rewriteTextBody) {
|
|
1396
|
-
const prefixed = rewriteShareOriginPaths(text, publicBase);
|
|
1561
|
+
const prefixed = rewriteShareOriginPaths(text, publicBase, portUrls);
|
|
1397
1562
|
if (prefixed !== text) {
|
|
1398
1563
|
text = prefixed;
|
|
1399
1564
|
mutated = true;
|