@maintainer-pro/ai-bridge 0.1.22 → 0.1.24

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maintainer-pro/ai-bridge",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
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.12",
31
+ "@maintainer-pro/ai-cli": "^0.1.13",
32
32
  "@maintainer-pro/ai-server": "^0.1.7"
33
33
  }
34
34
  }
package/src/daemon.mjs CHANGED
@@ -16,6 +16,7 @@ import os from "node:os";
16
16
  import path from "node:path";
17
17
  import readline from "node:readline";
18
18
  import { fileURLToPath, pathToFileURL } from "node:url";
19
+ import { createRequire } from "node:module";
19
20
  import { createLogger, ensureProjectDataDir } from "@maintainer-pro/ai-cli";
20
21
  import { findIife, startAiServer } from "@maintainer-pro/ai-server";
21
22
  import {
@@ -39,7 +40,9 @@ import {
39
40
  } from "./discarded-tunnels.mjs";
40
41
 
41
42
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
43
+ const requireFromHere = createRequire(import.meta.url);
42
44
  const PACKAGE_VERSION = readPackageVersion();
45
+ const PACKAGE_VERSIONS = readPackageVersions();
43
46
  const HEARTBEAT_MS = 15_000;
44
47
  const WS_PING_MS = 10_000;
45
48
  const WS_RECONNECT_MIN_MS = 1_000;
@@ -157,6 +160,53 @@ function readPackageVersion() {
157
160
  }
158
161
  }
159
162
 
163
+ function readDepPackageVersion(name) {
164
+ const files = [];
165
+ try {
166
+ files.push(requireFromHere.resolve(`${name}/package.json`));
167
+ } catch {
168
+ /* try nested next */
169
+ }
170
+ try {
171
+ const serverDir = path.dirname(
172
+ requireFromHere.resolve("@maintainer-pro/ai-server/package.json")
173
+ );
174
+ files.push(path.join(serverDir, "node_modules", name, "package.json"));
175
+ files.push(path.join(serverDir, "..", name.replace("@maintainer-pro/", ""), "package.json"));
176
+ } catch {
177
+ /* ignore */
178
+ }
179
+ for (const file of files) {
180
+ try {
181
+ const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
182
+ if (typeof pkg.version === "string" && pkg.version) return pkg.version;
183
+ } catch {
184
+ /* try next */
185
+ }
186
+ }
187
+ return null;
188
+ }
189
+
190
+ function readPackageVersions() {
191
+ return {
192
+ bridge: PACKAGE_VERSION,
193
+ cli: readDepPackageVersion("@maintainer-pro/ai-cli"),
194
+ server: readDepPackageVersion("@maintainer-pro/ai-server"),
195
+ ui: readDepPackageVersion("@maintainer-pro/ai-ui"),
196
+ };
197
+ }
198
+
199
+ function formatPackageVersions(versions = PACKAGE_VERSIONS) {
200
+ return [
201
+ versions.bridge && `bridge ${versions.bridge}`,
202
+ versions.cli && `cli ${versions.cli}`,
203
+ versions.server && `server ${versions.server}`,
204
+ versions.ui && `ui ${versions.ui}`,
205
+ ]
206
+ .filter(Boolean)
207
+ .join(" · ");
208
+ }
209
+
160
210
  async function warnIfBridgeOutdated() {
161
211
  const fromWorkspace = path
162
212
  .normalize(__dirname)
@@ -2259,6 +2309,7 @@ function shareProxyContext(msg, ws, appId) {
2259
2309
  acceptEncoding,
2260
2310
  port: localPortForProxy(ws, appId),
2261
2311
  portUrls: { ...fromWs, ...fromMsg },
2312
+ bypassCors: msg?.bypassCors === true,
2262
2313
  };
2263
2314
  }
2264
2315
 
@@ -2292,9 +2343,13 @@ function replyShareInterceptor(id, ctx, path) {
2292
2343
  let body = "";
2293
2344
  if (pathname === "/__mp/sw.js") {
2294
2345
  headers["service-worker-allowed"] = tokenRoot;
2295
- body = shareServiceWorkerScript(ctx.portUrls, tokenRoot);
2346
+ body = shareServiceWorkerScript(ctx.portUrls, tokenRoot, ctx.bypassCors);
2296
2347
  } else {
2297
- body = shareShimScript(publicPathPrefix(ctx.publicBase), ctx.portUrls);
2348
+ body = shareShimScript(
2349
+ publicPathPrefix(ctx.publicBase),
2350
+ ctx.portUrls,
2351
+ ctx.bypassCors
2352
+ );
2298
2353
  }
2299
2354
  replyProxyHttp(id, 200, headers, body);
2300
2355
  return true;
@@ -2325,6 +2380,7 @@ function bridgeEmbedConfigJs(ws) {
2325
2380
  logLevel: "debug",
2326
2381
  maintainerProUrl: bridgeCfg?.adminUrl || "",
2327
2382
  maintainerProApiKey: String(store.clientKey || "").trim(),
2383
+ versions: PACKAGE_VERSIONS,
2328
2384
  };
2329
2385
  return `window.__MAINTAINER_PRO__=${JSON.stringify(payload)};`;
2330
2386
  }
@@ -2425,6 +2481,234 @@ async function handleAiProxyHttpFromAdmin(msg, ws) {
2425
2481
  });
2426
2482
  }
2427
2483
 
2484
+ const EXTERNAL_PROXY_TIMEOUT_MS = 10 * 60 * 1000;
2485
+ const EXTERNAL_PROXY_MAX_REDIRECTS = 5;
2486
+ const EXTERNAL_PROXY_DROP_HEADERS = new Set([
2487
+ "cookie",
2488
+ "set-cookie",
2489
+ "host",
2490
+ "origin",
2491
+ "referer",
2492
+ "referrer",
2493
+ "connection",
2494
+ "keep-alive",
2495
+ "transfer-encoding",
2496
+ "upgrade",
2497
+ "content-length",
2498
+ "te",
2499
+ "trailer",
2500
+ "x-mp-target",
2501
+ "x-forwarded-proto",
2502
+ "x-forwarded-host",
2503
+ "x-forwarded-for",
2504
+ ]);
2505
+
2506
+ function parseExternalProxyUrl(value) {
2507
+ let parsed;
2508
+ try {
2509
+ parsed = new URL(String(value || ""));
2510
+ } catch {
2511
+ return null;
2512
+ }
2513
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
2514
+ const parts = parsed.pathname.split("/").filter(Boolean);
2515
+ if (parts[0] === "p" && parts[2] === "__cors") return null;
2516
+ return parsed;
2517
+ }
2518
+
2519
+ function externalProxyHeaders(incoming, targetHost) {
2520
+ /** @type {Record<string, string>} */
2521
+ const headers = {};
2522
+ if (incoming && typeof incoming === "object") {
2523
+ for (const [key, value] of Object.entries(incoming)) {
2524
+ const lower = String(key).toLowerCase();
2525
+ if (EXTERNAL_PROXY_DROP_HEADERS.has(lower)) continue;
2526
+ if (lower.startsWith("sec-fetch-")) continue;
2527
+ if (typeof value === "string" && value) headers[key] = value;
2528
+ }
2529
+ }
2530
+ headers.host = targetHost;
2531
+ return headers;
2532
+ }
2533
+
2534
+ function failExternalProxyHttp(id, error) {
2535
+ proxyHttpReqs.delete(id);
2536
+ bridgeSend({
2537
+ type: "proxy.http.error",
2538
+ id,
2539
+ error: error instanceof Error ? error.message : String(error || "Upstream error"),
2540
+ });
2541
+ }
2542
+
2543
+ function streamExternalProxyHttp(id, res) {
2544
+ const stream = randomBytes(8).toString("hex");
2545
+ /** @type {Record<string, string>} */
2546
+ const outHeaders = {};
2547
+ for (const [key, value] of Object.entries(res.headers || {})) {
2548
+ if (value == null) continue;
2549
+ const lower = String(key).toLowerCase();
2550
+ if (lower === "set-cookie" || lower === "cookie") continue;
2551
+ outHeaders[key] = Array.isArray(value) ? value.join(", ") : String(value);
2552
+ }
2553
+ bridgeSend({
2554
+ type: "proxy.http.start",
2555
+ id,
2556
+ stream,
2557
+ status: res.statusCode || 502,
2558
+ headers: outHeaders,
2559
+ });
2560
+ res.on("data", (chunk) => {
2561
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2562
+ for (let offset = 0; offset < buf.length; offset += PROXY_CHUNK_BYTES) {
2563
+ const end = Math.min(offset + PROXY_CHUNK_BYTES, buf.length);
2564
+ bridgeSend({
2565
+ type: "proxy.http.chunk",
2566
+ id,
2567
+ stream,
2568
+ data: Buffer.from(buf.subarray(offset, end)).toString("base64"),
2569
+ eof: false,
2570
+ });
2571
+ }
2572
+ });
2573
+ res.on("end", () => {
2574
+ proxyHttpReqs.delete(id);
2575
+ bridgeSend({
2576
+ type: "proxy.http.chunk",
2577
+ id,
2578
+ stream,
2579
+ data: "",
2580
+ eof: true,
2581
+ });
2582
+ });
2583
+ res.on("error", (err) => {
2584
+ failExternalProxyHttp(id, err);
2585
+ });
2586
+ }
2587
+
2588
+ function fetchExternalProxyUrl(entry, url, method, headers, body, redirectsLeft) {
2589
+ const parsed = parseExternalProxyUrl(url);
2590
+ if (!parsed) {
2591
+ failExternalProxyHttp(entry.id, "Invalid external URL");
2592
+ return;
2593
+ }
2594
+ const lib = parsed.protocol === "https:" ? https : http;
2595
+ /** @type {Record<string, string>} */
2596
+ const reqHeaders = { ...headers, host: parsed.host };
2597
+ const sendBody =
2598
+ body?.length && method !== "GET" && method !== "HEAD" ? body : null;
2599
+ if (sendBody) reqHeaders["content-length"] = String(sendBody.length);
2600
+ else delete reqHeaders["content-length"];
2601
+
2602
+ let req;
2603
+ try {
2604
+ req = lib.request(
2605
+ {
2606
+ protocol: parsed.protocol,
2607
+ hostname: parsed.hostname,
2608
+ port: parsed.port || undefined,
2609
+ path: `${parsed.pathname}${parsed.search}`,
2610
+ method,
2611
+ headers: reqHeaders,
2612
+ },
2613
+ (res) => {
2614
+ const status = res.statusCode || 502;
2615
+ const loc = res.headers.location;
2616
+ if (
2617
+ loc &&
2618
+ status >= 300 &&
2619
+ status < 400 &&
2620
+ redirectsLeft > 0
2621
+ ) {
2622
+ res.resume();
2623
+ let next;
2624
+ try {
2625
+ next = new URL(loc, parsed).href;
2626
+ } catch {
2627
+ failExternalProxyHttp(entry.id, "Invalid redirect");
2628
+ return;
2629
+ }
2630
+ const preserve = status === 307 || status === 308;
2631
+ const nextMethod = preserve
2632
+ ? method
2633
+ : method === "HEAD"
2634
+ ? "HEAD"
2635
+ : "GET";
2636
+ const nextBody =
2637
+ preserve && nextMethod !== "GET" && nextMethod !== "HEAD"
2638
+ ? body
2639
+ : Buffer.alloc(0);
2640
+ fetchExternalProxyUrl(
2641
+ entry,
2642
+ next,
2643
+ nextMethod,
2644
+ headers,
2645
+ nextBody,
2646
+ redirectsLeft - 1
2647
+ );
2648
+ return;
2649
+ }
2650
+ streamExternalProxyHttp(entry.id, res);
2651
+ }
2652
+ );
2653
+ } catch (err) {
2654
+ failExternalProxyHttp(entry.id, err);
2655
+ return;
2656
+ }
2657
+ req.setTimeout(EXTERNAL_PROXY_TIMEOUT_MS, () => {
2658
+ req.destroy(new Error("Upstream timeout"));
2659
+ });
2660
+ req.on("error", (err) => {
2661
+ failExternalProxyHttp(entry.id, err);
2662
+ });
2663
+ entry.req = req;
2664
+ if (sendBody) req.write(sendBody);
2665
+ req.end();
2666
+ }
2667
+
2668
+ function startExternalProxyHttp(entry) {
2669
+ const body = Buffer.concat(entry.chunks || []);
2670
+ fetchExternalProxyUrl(
2671
+ entry,
2672
+ entry.url,
2673
+ entry.method,
2674
+ entry.headers,
2675
+ body,
2676
+ EXTERNAL_PROXY_MAX_REDIRECTS
2677
+ );
2678
+ }
2679
+
2680
+ function handleExternalProxyHttpFromAdmin(msg) {
2681
+ const id = typeof msg.id === "string" ? msg.id : "";
2682
+ const parsed = parseExternalProxyUrl(msg.externalUrl);
2683
+ if (!id) return;
2684
+ if (!parsed) {
2685
+ failExternalProxyHttp(id, "Invalid external URL");
2686
+ return;
2687
+ }
2688
+ const existing = proxyHttpReqs.get(id);
2689
+ if (existing) {
2690
+ destroyProxyHttpReq(existing);
2691
+ proxyHttpReqs.delete(id);
2692
+ }
2693
+ const method = String(msg.method || "GET").toUpperCase();
2694
+ const initialBody =
2695
+ typeof msg.body === "string" && msg.body
2696
+ ? Buffer.from(msg.body, "base64")
2697
+ : null;
2698
+ const entry = {
2699
+ req: null,
2700
+ external: true,
2701
+ id,
2702
+ url: parsed.href,
2703
+ method,
2704
+ headers: externalProxyHeaders(msg.headers, parsed.host),
2705
+ chunks: [],
2706
+ };
2707
+ proxyHttpReqs.set(id, entry);
2708
+ if (initialBody?.length) entry.chunks.push(initialBody);
2709
+ if (msg.bodyEof !== false) startExternalProxyHttp(entry);
2710
+ }
2711
+
2428
2712
  function handleProxyHttpFromAdmin(msg) {
2429
2713
  const id = typeof msg.id === "string" ? msg.id : "";
2430
2714
  const sandboxId = typeof msg.sandboxId === "string" ? msg.sandboxId : "";
@@ -2439,6 +2723,10 @@ function handleProxyHttpFromAdmin(msg) {
2439
2723
  });
2440
2724
  return;
2441
2725
  }
2726
+ if (typeof msg.externalUrl === "string" && msg.externalUrl.trim()) {
2727
+ handleExternalProxyHttpFromAdmin(msg);
2728
+ return;
2729
+ }
2442
2730
  if (isAiServerAppId(appId, ws)) {
2443
2731
  void handleAiProxyHttpFromAdmin(msg, ws);
2444
2732
  return;
@@ -2651,11 +2939,16 @@ function handleProxyHttpBodyFromAdmin(msg) {
2651
2939
  const id = typeof msg.id === "string" ? msg.id : "";
2652
2940
  const entry = proxyHttpReqs.get(id);
2653
2941
  if (!entry) return;
2654
- const req = entry.req || entry;
2655
2942
  const chunk =
2656
2943
  typeof msg.data === "string" && msg.data
2657
2944
  ? Buffer.from(msg.data, "base64")
2658
2945
  : null;
2946
+ if (entry.external) {
2947
+ if (chunk?.length) entry.chunks.push(chunk);
2948
+ if (msg.eof === true) startExternalProxyHttp(entry);
2949
+ return;
2950
+ }
2951
+ const req = entry.req || entry;
2659
2952
  if (entry.rewrite) {
2660
2953
  if (chunk?.length) entry.chunks.push(chunk);
2661
2954
  if (msg.eof === true) {
@@ -4834,6 +5127,7 @@ async function sendHeartbeat(cfg, folders, localStates) {
4834
5127
  hostname: os.hostname(),
4835
5128
  platform: `${os.platform()}-${os.arch()}`,
4836
5129
  bridgeVersion: PACKAGE_VERSION,
5130
+ packageVersions: PACKAGE_VERSIONS,
4837
5131
  folders,
4838
5132
  issues: await buildIssues(cfg, localStates),
4839
5133
  workspaces: localStates.map((st) => ({
@@ -4866,6 +5160,7 @@ function buildLightHeartbeatPayload(cfg, folders) {
4866
5160
  hostname: os.hostname(),
4867
5161
  platform: `${os.platform()}-${os.arch()}`,
4868
5162
  bridgeVersion: PACKAGE_VERSION,
5163
+ packageVersions: PACKAGE_VERSIONS,
4869
5164
  folders,
4870
5165
  };
4871
5166
  }
@@ -4887,6 +5182,7 @@ async function buildHeartbeatPayload(cfg, folders, localStates) {
4887
5182
  hostname: os.hostname(),
4888
5183
  platform: `${os.platform()}-${os.arch()}`,
4889
5184
  bridgeVersion: PACKAGE_VERSION,
5185
+ packageVersions: PACKAGE_VERSIONS,
4890
5186
  folders,
4891
5187
  issues: await buildIssues(cfg, localStates),
4892
5188
  workspaces: localStates.map((st) => ({
@@ -5021,6 +5317,7 @@ async function pairFlow(args) {
5021
5317
  hostname: os.hostname(),
5022
5318
  platform: `${os.platform()}-${os.arch()}`,
5023
5319
  bridgeVersion: PACKAGE_VERSION,
5320
+ packageVersions: PACKAGE_VERSIONS,
5024
5321
  name: os.hostname(),
5025
5322
  });
5026
5323
 
@@ -5048,9 +5345,9 @@ async function main() {
5048
5345
  process.exit(0);
5049
5346
  }
5050
5347
 
5051
- logger.debug(
5052
- { logLevel: logger.level, nodeEnv: process.env.NODE_ENV },
5053
- "bridge starting"
5348
+ logger.info(
5349
+ { versions: PACKAGE_VERSIONS },
5350
+ `bridge v${PACKAGE_VERSION} starting (${formatPackageVersions()})`
5054
5351
  );
5055
5352
  void warnIfBridgeOutdated();
5056
5353
 
@@ -155,11 +155,33 @@ function isImmutableAssetPath(path) {
155
155
  return (
156
156
  /\/_next\/static\//.test(p) ||
157
157
  /\/__nextjs_font\//.test(p) ||
158
- /\/node_modules\/\.vite\//.test(p) ||
159
158
  /\.[0-9a-f]{8,}\.(?:js|css|woff2?)$/i.test(p)
160
159
  );
161
160
  }
162
161
 
162
+ function isViteDevSourcePath(path) {
163
+ const raw = String(path || "");
164
+ const p = raw.split("?")[0] || "";
165
+ if (/[?&]t=\d+/.test(raw)) return true;
166
+ if (/\/(?:@vite(?:\/|$)|@react-refresh|@fs\/|@id\/)/.test(p)) return true;
167
+ if (/\/node_modules\/\.vite\//.test(p)) return true;
168
+ if (/\/src\//.test(p)) return true;
169
+ if (
170
+ /\.(?:m?[jt]sx?|vue|svelte|css|scss|sass|less)$/i.test(p) &&
171
+ !/\/node_modules\//.test(p)
172
+ ) {
173
+ return true;
174
+ }
175
+ return false;
176
+ }
177
+
178
+ function isDocumentPath(path) {
179
+ const p = String(path || "").split("?")[0] || "";
180
+ if (!p || p === "/") return true;
181
+ if (/\.html?$/i.test(p)) return true;
182
+ return !/\.[A-Za-z0-9]+$/.test(p);
183
+ }
184
+
163
185
  function isNoStorePath(path) {
164
186
  const p = String(path || "").split("?")[0] || "";
165
187
  return (
@@ -169,11 +191,9 @@ function isNoStorePath(path) {
169
191
  /\/_next\/webpack-hmr/i.test(p) ||
170
192
  /\/_next\/webpack\/hmr/i.test(p) ||
171
193
  /\/__nextjs_original-stack-frames/i.test(p) ||
172
- /\/@vite(?:\/|$)/.test(p) ||
173
- /\/@react-refresh/.test(p) ||
174
- /\/@fs\//.test(p) ||
175
- /\/@id\//.test(p) ||
176
- /\/__mp\//.test(p)
194
+ /\/__mp\//.test(p) ||
195
+ isViteDevSourcePath(path) ||
196
+ isDocumentPath(path)
177
197
  );
178
198
  }
179
199
 
@@ -396,12 +416,12 @@ export function shareTokenRoot(publicBase) {
396
416
  return prefix.endsWith("/") ? prefix : `${prefix}/`;
397
417
  }
398
418
 
399
- export function shareShimScript(pathPrefix, portUrls) {
400
- return `(${shareProxyShim.toString()})(${JSON.stringify(pathPrefix || "")},${JSON.stringify(portUrls || {})},${rewriteMappedLocalUrls.toString()});`;
419
+ export function shareShimScript(pathPrefix, portUrls, bypassCors) {
420
+ return `(${shareProxyShim.toString()})(${JSON.stringify(pathPrefix || "")},${JSON.stringify(portUrls || {})},${rewriteMappedLocalUrls.toString()},${JSON.stringify(Boolean(bypassCors))});`;
401
421
  }
402
422
 
403
- export function shareServiceWorkerScript(portUrls, tokenRoot) {
404
- return `(${shareServiceWorkerMain.toString()})(${JSON.stringify(portUrls || {})},${JSON.stringify(tokenRoot || "/")},${rewriteMappedLocalUrls.toString()});`;
423
+ export function shareServiceWorkerScript(portUrls, tokenRoot, bypassCors) {
424
+ return `(${shareServiceWorkerMain.toString()})(${JSON.stringify(portUrls || {})},${JSON.stringify(tokenRoot || "/")},${rewriteMappedLocalUrls.toString()},${JSON.stringify(Boolean(bypassCors))});`;
405
425
  }
406
426
 
407
427
  function rewriteHeaderUrls(headers, publicBase, port, portUrls) {
@@ -596,7 +616,7 @@ function gzipIfRequested(payload, headers, acceptEncoding) {
596
616
 
597
617
  function rewriteCacheKey(publicBase, path) {
598
618
  if (!isImmutableAssetPath(path) && !isLongCacheScriptPath(path)) return null;
599
- return `${publicBase || ""}\0${String(path || "").split("?")[0]}`;
619
+ return `${publicBase || ""}\0${String(path || "")}`;
600
620
  }
601
621
 
602
622
  function rememberRewrite(key, payload, status, headers, etag) {
@@ -698,6 +718,19 @@ function isShareAssetPath(path) {
698
718
  );
699
719
  }
700
720
 
721
+ function rewriteShareAsLocalEnv(body) {
722
+ let out = String(body);
723
+ out = out.replace(
724
+ /(\/\.\*localhost\.\*\/\.test\()([^)]+)(\))/g,
725
+ "($1$2$3||location.pathname.indexOf(\"/p/\")===0)"
726
+ );
727
+ out = out.replace(
728
+ /((?:window\.)?location\.hostname)\s*===\s*(['"])localhost\2/g,
729
+ "($1===$2localhost$2||location.pathname.indexOf(\"/p/\")===0)"
730
+ );
731
+ return out;
732
+ }
733
+
701
734
  function prefixQuotedAssetPaths(body, pathPrefix) {
702
735
  if (!pathPrefix) return body;
703
736
  return String(body).replace(/(["'`])(\/(?!\/)[^"'`]*)/g, (full, q, path) => {
@@ -844,6 +877,7 @@ function prefixRootPaths(body, publicBase, contentType = "") {
844
877
  const css = mime === "text/css" || (!isCode && !html && /css/.test(mime));
845
878
  if (!html && !css) {
846
879
  let code = rewriteViteBaseLiterals(body, pathPrefix);
880
+ code = rewriteShareAsLocalEnv(code);
847
881
  code = prefixQuotedAssetPaths(code, pathPrefix);
848
882
  code = code.replace(
849
883
  /(?<![A-Za-z0-9])\/__nextjs_/g,
@@ -913,7 +947,7 @@ function isHtmlDocument(headers, body) {
913
947
 
914
948
  function isScriptRequestPath(path) {
915
949
  const p = String(path || "").split("?")[0]?.toLowerCase() || "";
916
- return /\.(?:m?js|cjs)$/.test(p);
950
+ return /\.(?:m?[jt]sx?|cjs)$/.test(p);
917
951
  }
918
952
 
919
953
  function isScriptOrJsonBody(headers, path) {
@@ -989,10 +1023,11 @@ function injectMaintainerProEmbed(html, aiPublicBase) {
989
1023
  /**
990
1024
  * Intercept every browser request and map listed app ports onto share URLs.
991
1025
  */
992
- function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
1026
+ function shareProxyShim(p, portMap, rewriteMappedLocalUrls, bypassCors) {
993
1027
  if (!p || window.__MP_SHARE_SHIM__) return;
994
1028
  window.__MP_SHARE_SHIM__ = 1;
995
1029
  window.__MP_PORT_MAP__ = portMap || {};
1030
+ window.__MP_BYPASS_CORS__ = Boolean(bypassCors);
996
1031
  function rewriteText(text) {
997
1032
  if (typeof text !== "string" || !text || typeof rewriteMappedLocalUrls !== "function") {
998
1033
  return text;
@@ -1094,46 +1129,67 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
1094
1129
  } catch (e) {}
1095
1130
  return v;
1096
1131
  }
1132
+ function isCorsProxyPath(pathname) {
1133
+ var parts = String(pathname || "").split("/").filter(Boolean);
1134
+ return parts[0] === "p" && parts[2] === "__cors";
1135
+ }
1136
+ function shareToken() {
1137
+ try {
1138
+ var parts = location.pathname.split("/").filter(Boolean);
1139
+ if (parts[0] === "p" && parts[1]) return parts[1];
1140
+ } catch (e) {}
1141
+ return "";
1142
+ }
1143
+ function corsProxy(v) {
1144
+ if (!bypassCors || typeof v !== "string" || !v) return v;
1145
+ if (!/^(https?:)\/\//i.test(v)) return v;
1146
+ try {
1147
+ var u = new URL(v);
1148
+ if (u.protocol !== "http:" && u.protocol !== "https:") return v;
1149
+ if (loopback(u.hostname)) return v;
1150
+ if (u.origin === location.origin) return v;
1151
+ if (isCorsProxyPath(u.pathname)) return v;
1152
+ var token = shareToken();
1153
+ if (!token) return v;
1154
+ return (
1155
+ location.origin +
1156
+ "/p/" +
1157
+ token +
1158
+ "/__cors?__mp_url=" +
1159
+ encodeURIComponent(u.href)
1160
+ );
1161
+ } catch (e) {}
1162
+ return v;
1163
+ }
1097
1164
  function addNet(v) {
1098
1165
  if (typeof v !== "string" || !v) return v;
1099
1166
  var mapped = mapLocal(v);
1100
1167
  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;
1168
+ if (/^(https?:|wss?:)\/\//i.test(v)) {
1169
+ try {
1170
+ var abs = new URL(v);
1171
+ if (!loopback(abs.hostname)) {
1172
+ if (/^wss?:/i.test(abs.protocol)) return v;
1173
+ return corsProxy(v);
1114
1174
  }
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);
1175
+ } catch (e) {}
1128
1176
  }
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;
1177
+ if (v.charAt(0) === "/" && v.charAt(1) !== "/") {
1178
+ var backend = backendBase();
1179
+ var path = v.split("?")[0];
1180
+ if (path === "/api/v1" || path.indexOf("/api/v1/") === 0 || path.indexOf("/p/") === 0) {
1181
+ return v;
1182
+ }
1183
+ if (
1184
+ backend &&
1185
+ !isAsset(path) &&
1186
+ (/^\/sreo(?:\/|$)/i.test(path) || /^\/api(?:\/|$)/i.test(path))
1187
+ ) {
1188
+ try {
1189
+ var rel = new URL(v, location.href);
1190
+ return backend + rel.pathname + rel.search + rel.hash;
1191
+ } catch (e) {}
1192
+ }
1137
1193
  }
1138
1194
  return addNav(v);
1139
1195
  }
@@ -1299,17 +1355,27 @@ function shareProxyShim(p, portMap, rewriteMappedLocalUrls) {
1299
1355
  try {
1300
1356
  var tokenRoot = p.replace(/\/[^/]+$/, "/");
1301
1357
  if (navigator.serviceWorker && tokenRoot.indexOf("/p/") === 0) {
1302
- navigator.serviceWorker.register(p + "/__mp/sw.js", { scope: tokenRoot });
1358
+ navigator.serviceWorker.register(p + "/__mp/sw.js", {
1359
+ scope: tokenRoot,
1360
+ updateViaCache: "none",
1361
+ });
1303
1362
  }
1304
1363
  } catch (e) {}
1305
1364
  }
1306
1365
 
1307
- function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
1366
+ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls, bypassCors) {
1308
1367
  self.addEventListener("install", function (event) {
1309
1368
  event.waitUntil(self.skipWaiting());
1310
1369
  });
1311
1370
  self.addEventListener("activate", function (event) {
1312
- event.waitUntil(self.clients.claim());
1371
+ event.waitUntil(
1372
+ self.clients.claim().then(function () {
1373
+ if (!self.caches) return;
1374
+ return self.caches.keys().then(function (keys) {
1375
+ return Promise.all(keys.map(function (key) { return self.caches.delete(key); }));
1376
+ });
1377
+ })
1378
+ );
1313
1379
  });
1314
1380
  function rewriteText(text) {
1315
1381
  if (typeof text !== "string" || !text) return text;
@@ -1352,37 +1418,62 @@ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
1352
1418
  }
1353
1419
  return "";
1354
1420
  }
1421
+ function isCorsProxyPath(pathname) {
1422
+ var parts = String(pathname || "").split("/").filter(Boolean);
1423
+ return parts[0] === "p" && parts[2] === "__cors";
1424
+ }
1425
+ function shareToken() {
1426
+ try {
1427
+ var parts = String(self.registration && self.registration.scope || self.location.pathname)
1428
+ .split("/")
1429
+ .filter(Boolean);
1430
+ if (parts[0] === "p" && parts[1]) return parts[1];
1431
+ } catch (e) {}
1432
+ return "";
1433
+ }
1434
+ function corsProxy(v) {
1435
+ if (!bypassCors || typeof v !== "string" || !v) return v;
1436
+ if (!/^(https?:)\/\//i.test(v)) return v;
1437
+ try {
1438
+ var u = new URL(v, self.location.href);
1439
+ if (u.protocol !== "http:" && u.protocol !== "https:") return v;
1440
+ if (loopback(u.hostname)) return v;
1441
+ if (u.origin === self.location.origin) return v;
1442
+ if (isCorsProxyPath(u.pathname)) return v;
1443
+ var token = shareToken();
1444
+ if (!token) return v;
1445
+ return (
1446
+ self.location.origin +
1447
+ "/p/" +
1448
+ token +
1449
+ "/__cors?__mp_url=" +
1450
+ encodeURIComponent(u.href)
1451
+ );
1452
+ } catch (e) {}
1453
+ return v;
1454
+ }
1355
1455
  function prefixWith(url, prefix) {
1356
- if (!prefix) return url;
1456
+ if (!prefix) return corsProxy(url);
1357
1457
  try {
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;
1458
+ if (/^(https?:|wss?:)\/\//i.test(url)) {
1459
+ var abs = new URL(url);
1460
+ if (!loopback(abs.hostname)) {
1461
+ if (/^wss?:/i.test(abs.protocol)) return url;
1462
+ return corsProxy(url);
1463
+ }
1368
1464
  }
1369
- var path = parsed.pathname || "/";
1465
+ var u = new URL(url, self.location.href);
1466
+ var path = u.pathname || "/";
1467
+ var backend = backendBase();
1370
1468
  if (path === "/api/v1" || path.indexOf("/api/v1/") === 0) return url;
1371
1469
  if (path.indexOf("/p/") === 0) return url;
1372
1470
  if (
1373
1471
  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)
1472
+ !/^(https?:|wss?:)\/\//i.test(url) &&
1473
+ (/^\/sreo(?:\/|$)/i.test(path) || /^\/api(?:\/|$)/i.test(path))
1380
1474
  ) {
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;
1475
+ return backend + path + (u.search || "") + (u.hash || "");
1384
1476
  }
1385
- var u = parsed;
1386
1477
  if (u.origin !== self.location.origin) return url;
1387
1478
  if (u.pathname === "/" || u.pathname === "") return url;
1388
1479
  if (u.pathname === prefix || u.pathname.indexOf(prefix + "/") === 0) return url;
@@ -1394,11 +1485,13 @@ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
1394
1485
  function mapUrl(v, prefix) {
1395
1486
  if (typeof v !== "string" || !v) return v;
1396
1487
  if (v.indexOf("/__mp/") !== -1) return v;
1488
+ if (v.indexOf("/__cors") !== -1) return v;
1397
1489
  return prefixWith(rewriteText(v), prefix);
1398
1490
  }
1399
1491
  self.addEventListener("fetch", function (event) {
1400
1492
  var req = event.request;
1401
1493
  if (req.url.indexOf("/__mp/") !== -1) return;
1494
+ if (req.url.indexOf("/__cors") !== -1) return;
1402
1495
  event.respondWith(
1403
1496
  (async function () {
1404
1497
  var client = null;
@@ -1429,6 +1522,7 @@ function shareServiceWorkerMain(portMap, tokenRoot, rewriteMappedLocalUrls) {
1429
1522
  credentials: req.credentials,
1430
1523
  redirect: req.redirect,
1431
1524
  referrer: req.referrer,
1525
+ cache: "no-store",
1432
1526
  };
1433
1527
  if (req.mode && req.mode !== "navigate") init.mode = req.mode;
1434
1528
  if (body !== undefined) init.body = body;
@@ -1550,14 +1644,14 @@ export function processShareHttpResponse(opts) {
1550
1644
  text = prefixRootPaths(text, publicBase, headers["content-type"] || "");
1551
1645
  mutated = true;
1552
1646
  }
1553
- if (Object.keys(portUrls).length && rewriteTextBody) {
1647
+ if (Object.keys(portUrls).length && rewriteTextBody && !isScriptOrJsonBody(headers, path)) {
1554
1648
  const mapped = rewriteMappedLocalUrls(text, portUrls);
1555
1649
  if (mapped !== text) {
1556
1650
  text = mapped;
1557
1651
  mutated = true;
1558
1652
  }
1559
1653
  }
1560
- if (publicBase && rewriteTextBody) {
1654
+ if (publicBase && rewriteTextBody && !isScriptOrJsonBody(headers, path)) {
1561
1655
  const prefixed = rewriteShareOriginPaths(text, publicBase, portUrls);
1562
1656
  if (prefixed !== text) {
1563
1657
  text = prefixed;