@maintainer-pro/ai-bridge 0.1.13 → 0.1.14

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.13",
3
+ "version": "0.1.14",
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.7",
32
- "@maintainer-pro/ai-server": "^0.1.6"
31
+ "@maintainer-pro/ai-cli": "^0.1.8",
32
+ "@maintainer-pro/ai-server": "^0.1.7"
33
33
  }
34
34
  }
package/src/daemon.mjs CHANGED
@@ -5200,6 +5200,12 @@ async function main() {
5200
5200
 
5201
5201
  if (args.pair || !cfg.token || !cfg.adminUrl) {
5202
5202
  cfg = await pairFlow(args);
5203
+ } else if (typeof args.adminUrl === "string" && args.adminUrl.trim()) {
5204
+ const next = args.adminUrl.replace(/\/$/, "");
5205
+ if (cfg.adminUrl && cfg.adminUrl !== next) {
5206
+ log(`admin URL ${cfg.adminUrl} → ${next}`);
5207
+ }
5208
+ cfg.adminUrl = next;
5203
5209
  }
5204
5210
 
5205
5211
  cfg.noAiServer = Boolean(args.noAiServer);
@@ -5557,6 +5563,11 @@ async function main() {
5557
5563
  clearHeartbeatTimer();
5558
5564
  clearPingTimer();
5559
5565
  if (socket === ws) socket = null;
5566
+ if (Number(code) === 1008) {
5567
+ warn(
5568
+ "Admin rejected this computer’s token. This admin is not the one in ~/.maintainer-pro/bridge.json. Generate a new pair code (Admin → Bridges → Add computer) and run the pair command."
5569
+ );
5570
+ }
5560
5571
  scheduleReconnect(code, reason);
5561
5572
  };
5562
5573
 
@@ -237,17 +237,36 @@ function notModifiedResult(headers, etag) {
237
237
 
238
238
  function rewriteLocation(value, publicBase, port) {
239
239
  if (!publicBase) return value;
240
+ const base = String(publicBase).replace(/\/$/, "");
241
+ const prefix = proxyPathPrefix(publicBase);
240
242
  try {
241
243
  const u = new URL(value, `http://127.0.0.1:${Number(port) || 0}`);
242
- if (u.hostname === "127.0.0.1" || u.hostname === "localhost") {
243
- return `${String(publicBase).replace(/\/$/, "")}${u.pathname}${u.search}${u.hash}`;
244
+ const host = String(u.hostname || "").toLowerCase();
245
+ const local =
246
+ host === "127.0.0.1" ||
247
+ host === "localhost" ||
248
+ host === "::1" ||
249
+ host === "0.0.0.0";
250
+ if (!local) return value;
251
+ let path = u.pathname || "/";
252
+ if (prefix && (path === prefix || path.startsWith(`${prefix}/`))) {
253
+ path = path.slice(prefix.length) || "/";
244
254
  }
255
+ return `${base}${path}${u.search}${u.hash}`;
245
256
  } catch {
246
257
  /* keep */
247
258
  }
248
259
  return value;
249
260
  }
250
261
 
262
+ function rewriteLinkHeader(value, publicBase) {
263
+ const prefix = proxyPathPrefix(publicBase);
264
+ if (!prefix || !value) return value;
265
+ return String(value).replace(/<(\/(?!\/)[^>\s]*)>/g, (full, path) =>
266
+ alreadyPrefixed(path, prefix) ? full : `<${prefix}${path}>`
267
+ );
268
+ }
269
+
251
270
  function gzipIfRequested(payload, headers, acceptEncoding) {
252
271
  if (payload.length < 1024) return payload;
253
272
  if (!/\bgzip\b/i.test(acceptEncoding || "")) return payload;
@@ -411,9 +430,38 @@ function alreadyPrefixed(path, pathPrefix) {
411
430
  return path === pathPrefix || path.startsWith(`${pathPrefix}/`);
412
431
  }
413
432
 
433
+ function rewriteNextFlightCanonical(body, pathPrefix) {
434
+ if (!pathPrefix || !body) return body;
435
+ const encoded = JSON.stringify(pathPrefix);
436
+ const escaped = pathPrefix.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
437
+ let out = body;
438
+ if (out.includes(`"c":["",""]`)) {
439
+ out = out.split(`"c":["",""]`).join(`"c":[${encoded}]`);
440
+ }
441
+ if (out.includes('\\"c\\":[\\"\\",\\"\\"]')) {
442
+ out = out
443
+ .split('\\"c\\":[\\"\\",\\"\\"]')
444
+ .join(`\\"c\\":[\\"${escaped}\\"]`);
445
+ }
446
+ out = out.replace(/("b":"[^"]+","p":)""/g, `$1${encoded}`);
447
+ out = out.replace(
448
+ /(\\?"b\\":\\?"[^"]+\\?",\\?"p\\":)\\?"\\?"/g,
449
+ `$1\\"${escaped}\\"`
450
+ );
451
+ if (out.includes(`"assetPrefix":""`)) {
452
+ out = out.split(`"assetPrefix":""`).join(`"assetPrefix":${encoded}`);
453
+ }
454
+ if (out.includes('\\"assetPrefix\\":\\"\\"')) {
455
+ out = out
456
+ .split('\\"assetPrefix\\":\\"\\"')
457
+ .join(`\\"assetPrefix\\":\\"${escaped}\\"`);
458
+ }
459
+ return out;
460
+ }
461
+
414
462
  function rewriteNextTurbopackBasePath(body, pathPrefix) {
415
463
  if (!pathPrefix) return body;
416
- let out = body;
464
+ let out = rewriteNextFlightCanonical(body, pathPrefix);
417
465
  if (out.includes("TURBOPACK compile-time value")) {
418
466
  const next = JSON.stringify(pathPrefix);
419
467
  out = out
@@ -486,6 +534,7 @@ function prefixRootPaths(body, publicBase, contentType = "") {
486
534
  out = out.replace(/\s+crossorigin(?:\s*=\s*(["']).*?\1)?/gi, "");
487
535
  }
488
536
  if (isNextDocument(out)) {
537
+ out = rewriteNextFlightCanonical(out, pathPrefix);
489
538
  out = prefixQuotedRoots(out, pathPrefix, ["/_next/", "/__nextjs_"]);
490
539
  out = out.replace(
491
540
  /(url\(\s*['"]?)(\/(?!\/)[^)"']*)/gi,
@@ -610,7 +659,7 @@ function injectNextProxyShim(html, publicBase) {
610
659
  return html;
611
660
  }
612
661
  const p = JSON.stringify(prefix);
613
- const script = `<script data-mp-proxy-next>(function(p){if(!p)return;function add(v){if(typeof v!=="string"||!v)return v;if(v.charAt(0)==="/"&&v.charAt(1)!=="/"){if(v===p||v.indexOf(p+"/")===0)return v;var root=p.slice(0,p.lastIndexOf("/"));if(root&&(v===root||v.indexOf(root+"/")===0)return v;if(v==="/api/v1"||v.indexOf("/api/v1/")===0)return v;return p+v}try{var u=new URL(v,location.href);var host=String(u.hostname||"").toLowerCase();if(host.charAt(0)==="["&&host.charAt(host.length-1)==="]")host=host.slice(1,-1);var local=host==="localhost"||host==="127.0.0.1"||host==="::1"||host==="0.0.0.0";if(!local){if(u.pathname===p){u.pathname="/";return u.toString()}if(u.pathname.indexOf(p+"/")===0){u.pathname=u.pathname.slice(p.length)||"/";return u.toString()}return v}var samePort=String(u.port||"")===String(location.port||"");if(samePort){u.pathname=add(u.pathname);return u.toString()}if(u.pathname===p||u.pathname.indexOf(p+"/")===0){u.protocol=location.protocol;u.host=location.host;return u.toString()}}catch(e){}return v}function mapSel(sel){if(typeof sel!=="string")return sel;var pairs=[["src=\\"/_next/","src=\\""+p+"/_next/"],["href=\\"/_next/","href=\\""+p+"/_next/"]];for(var i=0;i<pairs.length;i++){if(sel.indexOf(pairs[i][0])!==-1)return sel.split(pairs[i][0]).join(pairs[i][1])}return sel}function patchQS(proto,name){var orig=proto[name];proto[name]=function(sel){var r=orig.call(this,sel);if(name==="querySelector"){if(r)return r}else if(r.length)return r;var s2=mapSel(sel);return s2===sel?r:orig.call(this,s2)}}patchQS(Document.prototype,"querySelector");patchQS(Document.prototype,"querySelectorAll");patchQS(Element.prototype,"querySelector");patchQS(Element.prototype,"querySelectorAll");var sa=Element.prototype.setAttribute;Element.prototype.setAttribute=function(n,v){if((n==="src"||n==="href")&&typeof v==="string")v=add(v);return sa.call(this,n,v)};function patchUrlProp(ctor,prop){try{var d=Object.getOwnPropertyDescriptor(ctor.prototype,prop);if(!d||!d.set)return;Object.defineProperty(ctor.prototype,prop,{configurable:true,enumerable:true,get:d.get,set:function(v){d.set.call(this,add(v))}})}catch(e){}}patchUrlProp(HTMLScriptElement,"src");patchUrlProp(HTMLLinkElement,"href");var f=window.fetch;window.fetch=function(input,init){if(typeof input==="string")input=add(input);else if(typeof Request!=="undefined"&&input instanceof Request)input=new Request(add(input.url),input);else if(typeof URL!=="undefined"&&input instanceof URL)input=new URL(add(input.href));return f.call(this,input,init)};var xo=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(m,u){if(typeof u==="string")arguments[1]=add(u);return xo.apply(this,arguments)};var ps=history.pushState.bind(history);history.pushState=function(s,t,u){if(typeof u==="string")u=add(u);return ps(s,t,u)};var rs=history.replaceState.bind(history);history.replaceState=function(s,t,u){if(typeof u==="string")u=add(u);return rs(s,t,u)};var WS=window.WebSocket;function WrappedWS(url,protocols){if(typeof url==="string")url=add(url);return protocols!==undefined?new WS(url,protocols):new WS(url)}WrappedWS.prototype=WS.prototype;WrappedWS.CONNECTING=WS.CONNECTING;WrappedWS.OPEN=WS.OPEN;WrappedWS.CLOSING=WS.CLOSING;WrappedWS.CLOSED=WS.CLOSED;window.WebSocket=WrappedWS})(${p})</script>`;
662
+ const script = `<script data-mp-proxy-next>(function(p){if(!p)return;function add(v){if(typeof v!=="string"||!v)return v;function collapse(path){var d=p+p;while(path.indexOf(d)===0)path=p+path.slice(d.length);return path}if(v.charAt(0)==="/"&&v.charAt(1)!=="/"){if(v===p||v.indexOf(p+"/")===0)return collapse(v);var root=p.slice(0,p.lastIndexOf("/"));if(root&&(v===root||v.indexOf(root+"/")===0))return v;if(v==="/api/v1"||v.indexOf("/api/v1/")===0)return v;return collapse(p+v)}try{var u=new URL(v,location.href);var host=String(u.hostname||"").toLowerCase();if(host.charAt(0)==="["&&host.charAt(host.length-1)==="]")host=host.slice(1,-1);var local=host==="localhost"||host==="127.0.0.1"||host==="::1"||host==="0.0.0.0";if(!local){if(u.pathname===p){u.pathname="/";return u.toString()}if(u.pathname.indexOf(p+"/")===0){u.pathname=u.pathname.slice(p.length)||"/";return u.toString()}return v}var samePort=String(u.port||"")===String(location.port||"");if(samePort){u.pathname=add(u.pathname);return u.toString()}if(u.pathname===p||u.pathname.indexOf(p+"/")===0){u.protocol=location.protocol;u.host=location.host;return u.toString()}u.pathname=add(u.pathname||"/");u.protocol=location.protocol;u.host=location.host;return u.toString()}catch(e){}return v}function mapSel(sel){if(typeof sel!=="string")return sel;var pairs=[["src=\\"/_next/","src=\\""+p+"/_next/"],["href=\\"/_next/","href=\\""+p+"/_next/"]];for(var i=0;i<pairs.length;i++){if(sel.indexOf(pairs[i][0])!==-1)return sel.split(pairs[i][0]).join(pairs[i][1])}return sel}function patchQS(proto,name){var orig=proto[name];proto[name]=function(sel){var r=orig.call(this,sel);if(name==="querySelector"){if(r)return r}else if(r.length)return r;var s2=mapSel(sel);return s2===sel?r:orig.call(this,s2)}}patchQS(Document.prototype,"querySelector");patchQS(Document.prototype,"querySelectorAll");patchQS(Element.prototype,"querySelector");patchQS(Element.prototype,"querySelectorAll");var sa=Element.prototype.setAttribute;Element.prototype.setAttribute=function(n,v){if((n==="src"||n==="href")&&typeof v==="string")v=add(v);return sa.call(this,n,v)};function patchUrlProp(ctor,prop){try{var d=Object.getOwnPropertyDescriptor(ctor.prototype,prop);if(!d||!d.set)return;Object.defineProperty(ctor.prototype,prop,{configurable:true,enumerable:true,get:d.get,set:function(v){d.set.call(this,add(v))}})}catch(e){}}patchUrlProp(HTMLScriptElement,"src");patchUrlProp(HTMLLinkElement,"href");var f=window.fetch;window.fetch=function(input,init){if(typeof input==="string")input=add(input);else if(typeof Request!=="undefined"&&input instanceof Request)input=new Request(add(input.url),input);else if(typeof URL!=="undefined"&&input instanceof URL)input=new URL(add(input.href));return f.call(this,input,init)};var xo=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(m,u){if(typeof u==="string")arguments[1]=add(u);return xo.apply(this,arguments)};var ps=history.pushState.bind(history);history.pushState=function(s,t,u){if(typeof u==="string")u=add(u);return ps(s,t,u)};var rs=history.replaceState.bind(history);history.replaceState=function(s,t,u){if(typeof u==="string")u=add(u);return rs(s,t,u)};var WS=window.WebSocket;function WrappedWS(url,protocols){if(typeof url==="string")url=add(url);return protocols!==undefined?new WS(url,protocols):new WS(url)}WrappedWS.prototype=WS.prototype;WrappedWS.CONNECTING=WS.CONNECTING;WrappedWS.OPEN=WS.OPEN;WrappedWS.CLOSING=WS.CLOSING;WrappedWS.CLOSED=WS.CLOSED;window.WebSocket=WrappedWS;try{var la=location.assign.bind(location);location.assign=function(u){return la(add(String(u)))};var lr=location.replace.bind(location);location.replace=function(u){return lr(add(String(u)))}}catch(e){}try{var hd=Object.getOwnPropertyDescriptor(Location.prototype,"href");if(hd&&hd.set){Object.defineProperty(location,"href",{configurable:true,enumerable:true,get:function(){return hd.get.call(location)},set:function(v){hd.set.call(location,add(String(v)))}})}}catch(e){}})(${p})</script>`;
614
663
  return html.replace(/<head([^>]*)>/i, `<head$1>${script}`);
615
664
  }
616
665
 
@@ -649,6 +698,9 @@ export function processShareHttpResponse(opts) {
649
698
  if (headers.location) {
650
699
  headers.location = rewriteLocation(headers.location, publicBase, port);
651
700
  }
701
+ if (headers.link) {
702
+ headers.link = rewriteLinkHeader(headers.link, publicBase);
703
+ }
652
704
 
653
705
  const cachedKey = rewriteCacheKey(publicBase, path);
654
706
  const hit =