@buoy-gg/network 7.0.77 → 7.0.79
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/README.md +68 -2
- package/lib/commonjs/expo-network.js +1 -0
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/index.web.js +1 -1
- package/lib/commonjs/netinfo.js +1 -0
- package/lib/commonjs/network/components/NetworkCopySettingsView.js +1 -1
- package/lib/commonjs/network/components/NetworkEventDetailView.js +2 -2
- package/lib/commonjs/network/components/NetworkEventDetailView.web.js +1 -1
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +2 -2
- package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +1 -1
- package/lib/commonjs/network/components/NetworkListScreen.js +1 -1
- package/lib/commonjs/network/components/NetworkModal.js +1 -1
- package/lib/commonjs/network/components/NetworkSavedScreen.js +1 -1
- package/lib/commonjs/network/conditions/NetworkConditionsControl.js +1 -1
- package/lib/commonjs/network/conditions/NetworkConditionsControl.test.js +1 -1
- package/lib/commonjs/network/conditions/NetworkConditionsIcon.js +1 -1
- package/lib/commonjs/network/conditions/NetworkFloatingTool.js +1 -1
- package/lib/commonjs/network/conditions/NetworkFloatingTool.test.js +1 -1
- package/lib/commonjs/network/conditions/connectivity/netInfoFacade.js +1 -0
- package/lib/commonjs/network/conditions/connectivity/patchNetwork.js +1 -0
- package/lib/commonjs/network/conditions/pacer.js +1 -0
- package/lib/commonjs/network/conditions/profiles.js +1 -0
- package/lib/commonjs/network/conditions/remoteState.js +1 -0
- package/lib/commonjs/network/conditions/store.js +1 -1
- package/lib/commonjs/network/conditions/wait.js +1 -1
- package/lib/commonjs/network/conditions/xhr.js +1 -1
- package/lib/commonjs/network/overrides/engine.js +1 -1
- package/lib/commonjs/network/overrides/matchRule.js +1 -1
- package/lib/commonjs/network/overrides/overrideRulesStore.js +1 -1
- package/lib/commonjs/network/sync/networkSyncAdapter.js +1 -1
- package/lib/commonjs/network/utils/generateNetworkCopyText.js +1 -0
- package/lib/commonjs/network/utils/networkListener.js +4 -4
- package/lib/module/expo-network.js +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.web.js +1 -1
- package/lib/module/netinfo.js +1 -0
- package/lib/module/network/components/NetworkCopySettingsView.js +3 -3
- package/lib/module/network/components/NetworkEventDetailView.js +2 -2
- package/lib/module/network/components/NetworkEventDetailView.web.js +2 -2
- package/lib/module/network/components/NetworkEventItemCompact.js +2 -2
- package/lib/module/network/components/NetworkEventItemCompact.web.js +1 -1
- package/lib/module/network/components/NetworkListScreen.js +1 -1
- package/lib/module/network/components/NetworkModal.js +1 -1
- package/lib/module/network/components/NetworkSavedScreen.js +1 -1
- package/lib/module/network/conditions/NetworkConditionsControl.js +1 -1
- package/lib/module/network/conditions/NetworkConditionsControl.test.js +1 -1
- package/lib/module/network/conditions/NetworkConditionsIcon.js +1 -1
- package/lib/module/network/conditions/NetworkFloatingTool.js +1 -1
- package/lib/module/network/conditions/NetworkFloatingTool.test.js +1 -1
- package/lib/module/network/conditions/connectivity/netInfoFacade.js +1 -0
- package/lib/module/network/conditions/connectivity/patchNetwork.js +1 -0
- package/lib/module/network/conditions/pacer.js +1 -0
- package/lib/module/network/conditions/profiles.js +1 -0
- package/lib/module/network/conditions/remoteState.js +1 -0
- package/lib/module/network/conditions/store.js +1 -1
- package/lib/module/network/conditions/wait.js +1 -1
- package/lib/module/network/conditions/xhr.js +1 -1
- package/lib/module/network/overrides/engine.js +1 -1
- package/lib/module/network/overrides/matchRule.js +1 -1
- package/lib/module/network/overrides/overrideRulesStore.js +1 -1
- package/lib/module/network/sync/networkSyncAdapter.js +1 -1
- package/lib/module/network/utils/generateNetworkCopyText.js +23 -22
- package/lib/module/network/utils/networkListener.js +4 -4
- package/lib/typescript/expo-network.d.ts +2 -0
- package/lib/typescript/index.d.ts +3 -2
- package/lib/typescript/index.web.d.ts +3 -2
- package/lib/typescript/netinfo.d.ts +3 -0
- package/lib/typescript/network/conditions/NetworkConditionsControl.d.ts +5 -2
- package/lib/typescript/network/conditions/NetworkFloatingTool.d.ts +4 -3
- package/lib/typescript/network/conditions/connectivity/netInfoFacade.d.ts +3 -0
- package/lib/typescript/network/conditions/connectivity/patchNetwork.d.ts +24 -0
- package/lib/typescript/network/conditions/pacer.d.ts +16 -0
- package/lib/typescript/network/conditions/profiles.d.ts +57 -0
- package/lib/typescript/network/conditions/remoteState.d.ts +4 -0
- package/lib/typescript/network/conditions/store.d.ts +45 -19
- package/lib/typescript/network/conditions/xhr.d.ts +1 -1
- package/lib/typescript/network/overrides/engine.d.ts +14 -0
- package/lib/typescript/network/overrides/matchRule.d.ts +3 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts +3 -0
- package/lib/typescript/network/overrides/types.d.ts +19 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts +27 -12
- package/lib/typescript/network/utils/networkListener.d.ts +4 -0
- package/lib/web/index.mjs +58 -57
- package/package.json +26 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"use strict";import{isBuoyRequest as
|
|
1
|
+
"use strict";import{paceByteCount as ue,paceResponse as le,uploadBodySize as he,uploadSize as pe,utf8Length as fe}from"../conditions/pacer";import{isBuoyRequest as ye}from"@buoy-gg/shared-ui";import{resolveRequestUrl as W}from"./resolveRequestUrl";import{nextRequestId as Y}from"./requestId";import{runConditionXhr as me}from"../conditions/xhr";import{snapshotNetworkCondition as re}from"../conditions/store";import{throwIfAborted as V,waitBeforeDispatch as be}from"../conditions/wait";import{accountCheckFor as ge,overrideForRequest as oe,overrideRulesLoaded as Re,overrideRulesNeedBody as we,overrideRulesReady as ie}from"../overrides/engine";import{runOverride as Le,hasPendingStandardRequest as He}from"../overrides/applyToXhr";import{canSynthesizeResponse as Q,synthesizeFetchError as qe,synthesizeResponse as Se}from"../overrides/applyToFetch";import{markForOutcome as ae}from"../overrides/types";import{httpStatusText as _e,xhrCompletionKind as Te}from"./httpCompletion";import{realNow as v}from"./realNow";let A;function ce(b){const e=globalThis.__buoyHeaderInjectors;if(!e||e.length===0)return void 0;let t;for(const s of e){try{const l=s(b);if(l)t={...t,...l}}catch{}}return t}function Ee(){if(A!==void 0)return A;A=null;try{if(typeof __DEV__!=="undefined"&&!__DEV__)return A;const b=require("react-native");const e=b?.NativeModules?.SourceCode;const t=e?.getConstants?.().scriptURL??e?.scriptURL;if(typeof t==="string"&&/^https?:\/\//.test(t)){const s=new URL(t);A=`${s.protocol}//${s.host}`}}catch{A=null}return A}let M=false;const ve=Symbol.for("buoy.earlyNetwork");function Oe(b){const e={};if(!b)return e;if(typeof Headers!=="undefined"&&b instanceof Headers)b.forEach((t,s)=>{e[s]=t});else if(Array.isArray(b))for(const[t,s]of b)e[t]=s;else Object.assign(e,b);return e}export const BUOY_FETCH_INTERCEPTOR_FLAG="__buoyNetworkFetchIntercepted";export const BUOY_XHR_INTERCEPTOR_FLAG="__buoyNetworkXhrIntercepted";const Xe=["text/event-stream","application/x-ndjson","application/stream+json"];const Z="[streaming\u2026]";let ee=false;function ke(){if(ee)return true;const b=globalThis.document;ee=!!b?.querySelector?.("[ng-version]");return ee}function de(b){if(!b)return false;const e=b.toLowerCase();return Xe.some(t=>e.includes(t))}const xe="__BUOY_INTERNAL_HOSTS__";function Ne(b){const e=globalThis[xe];if(!(e instanceof Set)||e.size===0)return false;let t;try{t=new URL(b).host.toLowerCase()}catch{return false}for(const s of e){if(typeof s==="string"&&s&&t===s.toLowerCase())return true}return false}class Be{listeners=[];isListening=false;patchedFetch=null;patchedXHROpen=null;patchedXHRSend=null;patchedXHRSetRequestHeader=null;fetchGeneration=0;xhrGeneration=0;constructor(){this.originalFetch=globalThis.fetch;this.originalXHROpen=XMLHttpRequest.prototype.open;this.originalXHRSend=XMLHttpRequest.prototype.send;this.originalXHRSetRequestHeader=XMLHttpRequest.prototype.setRequestHeader}shouldIgnoreUrl(e){if(ye(e))return true;try{const t=new URL(e);if(t.hostname==="keygen.sh"||t.hostname.endsWith(".keygen.sh"))return true;if((t.hostname==="buoy.gg"||t.hostname==="www.buoy.gg")&&(t.pathname.startsWith("/api/license")||t.pathname.startsWith("/api/settings/")))return true;const s=t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="10.0.2.2";if(s&&["8081","8802"].includes(t.port))return true;const l=Ee();if(l&&`${t.protocol}//${t.host}`===l)return true}catch{return false}return Ne(e)}emit(e){this.listeners.forEach(t=>{try{t(e)}catch(s){}})}parseUrl(e){let t=null;const s=e.indexOf("?");if(s>-1){t={};e.substring(s+1).split("&").forEach(l=>{const[u,i]=l.split("=");if(u&&i!==void 0){t[u]=decodeURIComponent(i.replace(/\+/g," "))}})}return{url:s>-1?e.substring(0,s):e,params:t}}async readStreamedBody(e,t=256*1024){const s=e.body;if(!s||typeof s.getReader!=="function"){const f=await e.text();return f.length>t?{body:`${f.slice(0,t)}
|
|
2
2
|
|
|
3
|
-
... [truncated]`,size:f.length}:{body:f,size:f.length}}const
|
|
3
|
+
... [truncated]`,size:f.length}:{body:f,size:f.length}}const l=s.getReader();const u=new TextDecoder;let i="";let p=0;let g=false;try{for(;;){const{done:f,value:a}=await l.read();if(f)break;p+=a?.byteLength??0;if(!g){i+=u.decode(a,{stream:true});if(p>=t){i=`${i.slice(0,t)}
|
|
4
4
|
|
|
5
|
-
... [truncated]`;
|
|
5
|
+
... [truncated]`;g=true;break}}}if(!g)i+=u.decode()}finally{try{void Promise.resolve(l.cancel()).catch(()=>{})}catch{}try{l.releaseLock()}catch{}}return{body:i,size:p}}async processResponseBody(e,t=1024*1024){try{const s=e.headers.get("content-length");if(s){const i=parseInt(s,10);if(!isNaN(i)&&i>t){return{body:`[Response too large: ${this.formatBytes(i)}]`,size:i,truncated:true}}}const l=await e.text();const u=l.length;if(u>t){const i=l.substring(0,t);const p=u-t;return{body:`${i}
|
|
6
6
|
|
|
7
|
-
... [truncated, ${this.formatBytes(h)} omitted]`,size:a,truncated:true}}try{return{body:JSON.parse(c),size:a,truncated:false}}catch{return{body:c,size:a,truncated:false}}}catch(n){return{body:"~~~ unable to read body ~~~",size:0,truncated:false}}}formatBytes(e){if(e===0)return"0 B";const t=1024;const n=["B","KB","MB","GB"];const c=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/Math.pow(t,c)*100)/100} ${n[c]}`}handleXHRResponse(e,t,n,c,a,r,h,R,f=false,i="xhr",d,H){const y=R?S()-R:0;const l=e._buoyTtfb;const _=l===void 0?void 0:{ttfb:l,download:Math.max(0,y-l)};if(f||e.status===0){this.emit({type:"error",timestamp:new Date,duration:y,request:{id:t||"unknown",url:n,method:c,headers:a,data:r,params:h||void 0,client:i},error:{message:f?"Request failed":"Network error or request aborted"},override:d,condition:H});return}let s;let p=0;try{const o=e.response;if(e.responseType==="json"&&o){s=o;p=JSON.stringify(o).length}else if(e.responseType===""||e.responseType==="text"){if(e.responseText){p=e.responseText.length;try{s=JSON.parse(e.responseText)}catch{s=e.responseText}}}else if(e.responseType==="arraybuffer"){if(o){try{const q=new TextDecoder("utf-8").decode(o);p=q.length;try{s=JSON.parse(q)}catch{s=q}}catch(q){s=`[arraybuffer response - ${o.byteLength||0} bytes]`;p=o.byteLength||0}}else{s=`[arraybuffer response - no data]`;p=0}}else if(e.responseType==="blob"){if(o instanceof Blob){s=`[blob response - ${o.size} bytes, type: ${o.type||"unknown"}]`;p=o.size}else if(o){try{s=typeof o==="string"?JSON.parse(o):o;p=JSON.stringify(s).length}catch{s=`[blob response - unable to parse]`;p=0}}else{s=`[blob response - no data]`;p=0}}else if(o){if(typeof o==="string"){s=o;p=o.length;try{s=JSON.parse(o)}catch{}}else if(typeof o==="object"){s=o;p=JSON.stringify(o).length}else{s=String(o);p=String(o).length}}}catch(o){s="~~~ unable to read body ~~~"}const b={};try{const o=e.getAllResponseHeaders();if(o){o.split("\r\n").forEach(q=>{if(q){const m=q.indexOf(": ");if(m>0){const T=q.substring(0,m).toLowerCase();const u=q.substring(m+2);b[T]=u}}})}}catch{}if(ae(e.status)==="response"){this.emit({type:"response",timestamp:new Date,duration:y,timings:_,request:{id:t||"unknown",url:n,method:c,headers:a,data:r,params:h||void 0,client:i},response:{status:e.status,statusText:ie(e.status,e.statusText),headers:b,body:s,size:p},override:d,condition:H})}else{this.emit({type:"error",timestamp:new Date,duration:y,request:{id:t||"unknown",url:n,method:c,headers:a,data:r,params:h||void 0,client:i},response:{status:e.status,statusText:e.statusText,headers:b,body:s,size:p},error:{message:"Network Error"},override:d,condition:H})}}isFetchInterceptionLive(){return globalThis.fetch[BUOY_FETCH_INTERCEPTOR_FLAG]===true}isXhrInterceptionLive(){return XMLHttpRequest.prototype.send[BUOY_XHR_INTERCEPTOR_FLAG]===true}isInterceptionLive(){return this.isFetchInterceptionLive()&&this.isXhrInterceptionLive()}startListening(){const e=this.isListening&&this.isFetchInterceptionLive();const t=this.isListening&&this.isXhrInterceptionLive();if(e&&t){return}if(!e){this.installFetchInterceptor()}if(!t){this.installXhrInterceptor()}this.isListening=true;if(__DEV__){}}installFetchInterceptor(){const e=this;const t=globalThis.fetch.bind(globalThis);this.originalFetch=globalThis.fetch;const n=++this.fetchGeneration;const c=async(a,r)=>{const h=B(typeof a==="string"?a:a instanceof URL?a.href:a.url);if(n!==e.fetchGeneration){return t(a,r)}if(r?.__buoyInternal||e.shouldIgnoreUrl(h)){const u=x;x=true;try{return t(a,r)}finally{x=u}}const R=S();const f=D("fetch");const i=typeof a==="object"&&"method"in a?a:void 0;const d=r?.method??i?.method??"GET";const H=r?.signal!==void 0?r.signal:i?.signal;J(H);const y=j(h);const{url:l,params:_}=e.parseUrl(h);let s={};const p=r?.headers??i?.headers;if(p){if(p instanceof Headers){p.forEach((u,L)=>{s[L]=u})}else if(Array.isArray(p)){p.forEach(([u,L])=>{s[u]=L})}else{s={...p}}}Object.assign(s,W(h));let b;if(r?.body){if(typeof r.body==="string"){try{b=JSON.parse(r.body)}catch{b=r.body}}else{b=r.body}}const o=s["X-Request-Client"]||s["x-request-client"]||"fetch";const q=y?.profile!=="offline"&&P()?te(h,d,s,typeof r?.body==="string"?r.body:void 0):null;if(q)await q;const m=y?.profile!=="offline"&&P()?$(h,d,s,typeof r?.body==="string"?r.body:void 0):null;const T=m?Y(m):void 0;e.emit({type:"request",timestamp:new Date,request:{id:f||"unknown",url:l,method:d,headers:s,data:b,params:_||void 0,client:o},override:T,condition:y});if(r?.body===void 0&&i?.body&&!i.bodyUsed){try{const u=i.clone();void e.readStreamedBody(u).then(({body:L})=>{try{b=JSON.parse(L)}catch{b=L}e.emit({type:"request-body",timestamp:new Date,request:{id:f||"unknown",url:l,method:d,data:b,client:o}})}).catch(()=>{})}catch{}}try{if(y||m)await ee((y?.delayMs??0)+(m?.delayMs??0),H);J(H);if(y?.profile==="offline")throw new TypeError("Network request failed (Buoy Offline)");if(m?.kind==="fail")throw re(m);let u;if(m?.kind==="respond"){u=oe(h,m)}else{const X=x;x=true;let w;try{w=t(a,r)}finally{x=X}u=await w}const L=S()-R;const E=typeof u.body?.getReader==="function"||V(u.headers?.get?.("content-type"));const I=u.clone();const{body:C,size:O}=E?{body:K,size:0}:await e.processResponseBody(I);const M=S()-R;const F=Math.max(0,M-L);const U=F>0?{ttfb:L,download:F}:void 0;const N={};u.headers.forEach((X,w)=>{N[w.toLowerCase()]=X});e.emit({type:"response",timestamp:new Date,duration:M,timings:U,request:{id:f||"unknown",url:l,method:d,headers:s,data:b,params:_||void 0,client:o},response:{status:u.status,statusText:u.statusText,headers:N,body:C,size:O},override:T,condition:y});if(E){const X=u.headers?.get?.("content-type");void e.readStreamedBody(I,V(X)?void 0:1024*1024).then(w=>{let G=w.body;if(X?.includes("json")){try{G=JSON.parse(w.body)}catch{}}e.emit({type:"response",timestamp:new Date,duration:S()-R,timings:U,request:{id:f||"unknown",url:l,method:d,headers:s,data:b,params:_||void 0,client:o},response:{status:u.status,statusText:u.statusText,headers:N,body:G,size:w.size},override:T,condition:y})}).catch(()=>{})}return u}catch(u){const L=S()-R;e.emit({type:"error",timestamp:new Date,duration:L,request:{id:f||"unknown",url:l,method:d,headers:s,data:b,params:_||void 0,client:o},error:{message:u instanceof Error?u.message:"Network error",stack:u instanceof Error?u.stack:void 0},override:T,condition:y});throw u}};c[BUOY_FETCH_INTERCEPTOR_FLAG]=true;this.patchedFetch=c;globalThis.fetch=this.patchedFetch}installXhrInterceptor(){const e=this;const t=XMLHttpRequest.prototype.open;const n=XMLHttpRequest.prototype.send;const c=XMLHttpRequest.prototype.setRequestHeader;this.originalXHROpen=t;this.originalXHRSend=n;this.originalXHRSetRequestHeader=c;const a=++this.xhrGeneration;const r=new WeakMap;const h=function(i,d,H,y,l){const _=t.call(this,i,d,H??true,y,l);if(a===e.xhrGeneration){r.get(this)?.();const s=this;s._buoyRequestId=D("xhr");s._method=i;s._url=B(d);s._buoyStartTime=S();s._requestHeaders={}}return _};const R=function(i,d){const H=this;if(a===e.xhrGeneration&&H._requestHeaders){H._requestHeaders[i]=d}return c.call(this,i,d)};const f=function(i){if(a!==e.xhrGeneration||x){return n.call(this,i)}if(ne(this))throw new DOMException("The request has already been sent.","InvalidStateError");if(this.readyState!==1||this._sent){return n.call(this,i)}const d=this;const H=d._buoyRequestId;const y=d._method||"GET";const l=d._url||"";const _=S();d._buoyStartTime=_;d._buoyTtfb=void 0;const s=d._requestHeaders||{};Object.assign(s,W(l));if(e.shouldIgnoreUrl(l)){return n.call(this,i)}const{url:p,params:b}=e.parseUrl(l);let o;if(i){if(typeof i==="string"){try{o=JSON.parse(i)}catch{o=i}}else{o=i}}const q=s["X-Request-Client"]||s["x-request-client"];const m=s["Accept"]||s["accept"]||"";const T=m.includes("application/json")&&m.includes("text/plain")&&m.includes("*/*")&&!he();const u=q||(T?"axios":"xhr");const L=j(l);const E=L?.profile==="offline"?null:$(l,y,s,typeof i==="string"?i:void 0);const I=E?Y(E):void 0;e.emit({type:"request",timestamp:new Date,request:{id:H||"unknown",url:p,method:y,headers:s,data:o,params:b||void 0,client:u},override:I,condition:L});let C=false;const O=(w=false)=>{if(C)return;C=true;e.handleXHRResponse(this,H||"unknown",p,y,s,o,b,_||0,w,u,I,L);M()};const M=()=>{r.delete(this);this.removeEventListener("load",F);this.removeEventListener("error",U);this.removeEventListener("abort",N);this.removeEventListener("readystatechange",X)};r.set(this,M);const F=()=>{O(false)};const U=()=>{O(true)};const N=()=>{O(true)};const X=()=>{if(this.readyState===2){const w=this;if(w._buoyTtfb===void 0&&w._buoyStartTime){w._buoyTtfb=S()-w._buoyStartTime}}if(this.readyState===4&&!C){O(false)}};this.addEventListener("load",F);this.addEventListener("error",U);this.addEventListener("abort",N);this.addEventListener("readystatechange",X);if(L){Z(this,l,L,E,()=>n.call(this,i));return}if(E){const w=se(this,l,E,()=>n.call(this,i));if(w)return}return n.call(this,i)};f[BUOY_XHR_INTERCEPTOR_FLAG]=true;this.patchedXHROpen=h;this.patchedXHRSend=f;this.patchedXHRSetRequestHeader=R;XMLHttpRequest.prototype.open=this.patchedXHROpen;XMLHttpRequest.prototype.send=this.patchedXHRSend;XMLHttpRequest.prototype.setRequestHeader=this.patchedXHRSetRequestHeader}stopListening(){if(!this.isListening){return}this.fetchGeneration++;this.xhrGeneration++;if(this.patchedFetch&&globalThis.fetch===this.patchedFetch){globalThis.fetch=this.originalFetch}if(this.patchedXHROpen&&XMLHttpRequest.prototype.open===this.patchedXHROpen){XMLHttpRequest.prototype.open=this.originalXHROpen}if(this.patchedXHRSend&&XMLHttpRequest.prototype.send===this.patchedXHRSend){XMLHttpRequest.prototype.send=this.originalXHRSend}if(this.patchedXHRSetRequestHeader&&XMLHttpRequest.prototype.setRequestHeader===this.patchedXHRSetRequestHeader){XMLHttpRequest.prototype.setRequestHeader=this.originalXHRSetRequestHeader}this.patchedFetch=null;this.patchedXHROpen=null;this.patchedXHRSend=null;this.patchedXHRSetRequestHeader=null;this.isListening=false;if(__DEV__){}}adoptEarlyRequests(){const e=globalThis.__BUOY_EARLY_NETWORK__;if(e?.version!==1)return;for(const t of e.adopt()){try{if(t.kind==="fetch")this.adoptEarlyFetch(t);else this.adoptEarlyXhr(t)}catch{}}}adoptEarlyFetch(e){const{input:t,init:n}=e;const c=typeof t==="object"&&"method"in t?t:void 0;const a=B(typeof t==="string"?t:t instanceof URL?t.href:t.url);if(this.shouldIgnoreUrl(a))return;const r=D("fetch");const h=n?.method??c?.method??"GET";const{url:R,params:f}=this.parseUrl(a);const i=de(n?.headers??c?.headers);let d=n?.body;if(typeof d==="string"){try{d=JSON.parse(d)}catch{}}const H=i["X-Request-Client"]||i["x-request-client"]||"fetch";const y=()=>({id:r,url:R,method:h,headers:i,data:d,params:f||void 0,client:H});this.emit({type:"request",timestamp:new Date(e.start),request:y()});if(e.requestCopy){void this.readStreamedBody(e.requestCopy).then(({body:l})=>{try{d=JSON.parse(l)}catch{d=l}this.emit({type:"request-body",timestamp:new Date,request:{id:r,url:R,method:h,data:d,client:H}})}).catch(()=>{})}void e.settled.then(async({response:l,clone:_,error:s,headersAt:p})=>{if(!l){this.emit({type:"error",timestamp:new Date,duration:p-e.start,request:y(),error:{message:s instanceof Error?s.message:"Network error",stack:s instanceof Error?s.stack:void 0}});return}const{body:b,size:o}=_?await this.processResponseBody(_):{body:K,size:0};const q=Math.max(0,S()-e.start);const m=p-e.start;const T={};l.headers.forEach((u,L)=>{T[L.toLowerCase()]=u});this.emit({type:"response",timestamp:new Date,duration:q,timings:q>m?{ttfb:m,download:q-m}:void 0,request:y(),response:{status:l.status,statusText:l.statusText,headers:T,body:b,size:o}})})}adoptEarlyXhr(e){const t=B(e.url);if(this.shouldIgnoreUrl(t))return;const n=D("xhr");const c=e.method.toUpperCase();const{url:a,params:r}=this.parseUrl(t);let h=e.body;if(typeof h==="string"){try{h=JSON.parse(h)}catch{}}const R=e.headers["X-Request-Client"]||e.headers["x-request-client"]||"xhr";this.emit({type:"request",timestamp:new Date(e.start),request:{id:n,url:a,method:c,headers:e.headers,data:h,params:r||void 0,client:R}});const f=e.xhr;const i=()=>{const d=(f._buoyEarlyEnd??S())-e.start;this.handleXHRResponse(f,n,a,c,e.headers,h,r,S()-d,false,R)};if(f.readyState===4)i();else f.addEventListener("loadend",i,{once:true})}addListener(e){this.listeners.push(e);return()=>{const t=this.listeners.indexOf(e);if(t>-1){this.listeners.splice(t,1)}}}removeAllListeners(){this.listeners=[]}get isActive(){return this.isListening}get listenerCount(){return this.listeners.length}}let v=null;const z=()=>{if(!v){v=new fe}return v};export const networkListener=z;export const startNetworkListener=()=>z().startListening();export const stopNetworkListener=()=>v?.stopListening();export const addNetworkListener=g=>z().addListener(g);export const removeAllNetworkListeners=()=>v?.removeAllListeners();export const isNetworkListening=()=>v?.isActive??false;export const getNetworkListenerCount=()=>v?.listenerCount??0;export const isNetworkInterceptionLive=()=>v?.isInterceptionLive()??false;
|
|
7
|
+
... [truncated, ${this.formatBytes(p)} omitted]`,size:u,truncated:true}}try{return{body:JSON.parse(l),size:u,truncated:false}}catch{return{body:l,size:u,truncated:false}}}catch(s){return{body:"~~~ unable to read body ~~~",size:0,truncated:false}}}formatBytes(e){if(e===0)return"0 B";const t=1024;const s=["B","KB","MB","GB"];const l=Math.floor(Math.log(e)/Math.log(t));return`${Math.round(e/Math.pow(t,l)*100)/100} ${s[l]}`}handleXHRResponse(e,t,s,l,u,i,p,g,f=false,a="xhr",n,y){const R=g?v()-g:0;const c=e._buoyTtfb;const L=c===void 0?void 0:{ttfb:c,download:Math.max(0,R-c)};if(f||e.status===0){this.emit({type:"error",timestamp:new Date,duration:R,request:{id:t||"unknown",url:s,method:l,headers:u,data:i,params:p||void 0,client:a},error:{message:f?"Request failed":"Network error or request aborted"},override:n,condition:y});return}let o;let h=0;try{const r=e.response;if(e.responseType==="json"&&r){o=r;h=JSON.stringify(r).length}else if(e.responseType===""||e.responseType==="text"){if(e.responseText){h=e.responseText.length;try{o=JSON.parse(e.responseText)}catch{o=e.responseText}}}else if(e.responseType==="arraybuffer"){if(r){try{const m=new TextDecoder("utf-8").decode(r);h=m.length;try{o=JSON.parse(m)}catch{o=m}}catch(m){o=`[arraybuffer response - ${r.byteLength||0} bytes]`;h=r.byteLength||0}}else{o=`[arraybuffer response - no data]`;h=0}}else if(e.responseType==="blob"){if(r instanceof Blob){o=`[blob response - ${r.size} bytes, type: ${r.type||"unknown"}]`;h=r.size}else if(r){try{o=typeof r==="string"?JSON.parse(r):r;h=JSON.stringify(o).length}catch{o=`[blob response - unable to parse]`;h=0}}else{o=`[blob response - no data]`;h=0}}else if(r){if(typeof r==="string"){o=r;h=r.length;try{o=JSON.parse(r)}catch{}}else if(typeof r==="object"){o=r;h=JSON.stringify(r).length}else{o=String(r);h=String(r).length}}}catch(r){o="~~~ unable to read body ~~~"}if(y?.downloadBytesPerSecond&&(!e.responseType||e.responseType==="text"||e.responseType==="json")){const r=e._response;if(typeof r==="string")h=fe(r)}const H={};try{const r=e.getAllResponseHeaders();if(r){r.split("\r\n").forEach(m=>{if(m){const w=m.indexOf(": ");if(w>0){const k=m.substring(0,w).toLowerCase();const q=m.substring(w+2);H[k]=q}}})}}catch{}if(Te(e.status)==="response"){this.emit({type:"response",timestamp:new Date,duration:R,timings:L,request:{id:t||"unknown",url:s,method:l,headers:u,data:i,params:p||void 0,client:a},response:{status:e.status,statusText:_e(e.status,e.statusText),headers:H,body:o,size:h},override:n,condition:y})}else{this.emit({type:"error",timestamp:new Date,duration:R,request:{id:t||"unknown",url:s,method:l,headers:u,data:i,params:p||void 0,client:a},response:{status:e.status,statusText:e.statusText,headers:H,body:o,size:h},error:{message:"Network Error"},override:n,condition:y})}}isFetchInterceptionLive(){return globalThis.fetch[BUOY_FETCH_INTERCEPTOR_FLAG]===true}isXhrInterceptionLive(){return XMLHttpRequest.prototype.send[BUOY_XHR_INTERCEPTOR_FLAG]===true}isInterceptionLive(){return this.isFetchInterceptionLive()&&this.isXhrInterceptionLive()}startListening(){const e=this.isListening&&this.isFetchInterceptionLive();const t=this.isListening&&this.isXhrInterceptionLive();if(e&&t){return}if(!e){this.installFetchInterceptor()}if(!t){this.installXhrInterceptor()}this.isListening=true;if(__DEV__){}}installFetchInterceptor(){const e=this;const t=globalThis.fetch.bind(globalThis);this.originalFetch=globalThis.fetch;const s=++this.fetchGeneration;const l=async(u,i)=>{const p=W(typeof u==="string"?u:u instanceof URL?u.href:u.url);if(s!==e.fetchGeneration){return t(u,i)}if(i?.__buoyInternal||e.shouldIgnoreUrl(p)){const d=M;M=true;try{return t(u,i)}finally{M=d}}const g=v();const f=Y("fetch");const a=typeof u==="object"&&"method"in u?u:void 0;const n=i?.method??a?.method??"GET";const y=i?.signal!==void 0?i.signal:a?.signal;V(y);const R=re(p);const c=R?.uploadBytesPerSecond?{...R,uploadCap:he(u,i)}:R;const{url:L,params:o}=e.parseUrl(p);let h={};const H=i?.headers??a?.headers;if(H){if(H instanceof Headers){H.forEach((d,_)=>{h[_]=d})}else if(Array.isArray(H)){H.forEach(([d,_])=>{h[d]=_})}else{h={...H}}}Object.assign(h,ce(p));let r;if(i?.body){if(typeof i.body==="string"){try{r=JSON.parse(i.body)}catch{r=i.body}}else{r=i.body}}const m=h["X-Request-Client"]||h["x-request-client"]||"fetch";if(c?.profile!=="offline"&&Q())await ie();let w=typeof i?.body==="string"?i.body:void 0;if(w===void 0&&i?.body===void 0&&a&&!a.bodyUsed&&n!=="GET"&&n!=="HEAD"&&we()){try{w=(await e.readStreamedBody(a.clone())).body}catch{}}const k=c?.profile!=="offline"&&Q()?ge(p,n,h,w):null;if(k)await k;const q=c?.profile!=="offline"&&Q()?oe(p,n,h,w):null;const O=q?ae(q):void 0;e.emit({type:"request",timestamp:new Date,request:{id:f||"unknown",url:L,method:n,headers:h,data:r,params:o||void 0,client:m},override:O,condition:c});const B=d=>{try{r=JSON.parse(d)}catch{r=d}e.emit({type:"request-body",timestamp:new Date,request:{id:f||"unknown",url:L,method:n,data:r,client:m}})};if(i?.body===void 0&&a&&typeof w==="string"){B(w)}else if(!c?.uploadBytesPerSecond&&i?.body===void 0&&a&&!a.bodyUsed&&n!=="GET"&&n!=="HEAD"){try{const d=a.clone();void e.readStreamedBody(d).then(({body:_})=>{if(_)B(_)}).catch(()=>{})}catch{}}try{if(c||q)await be((c?.delayMs??0)+(q?.delayMs??0),y);V(y);if(c?.profile==="offline")throw new TypeError("Network request failed (Buoy Offline)");if(q?.kind==="fail")throw qe(q);if(c?.uploadBytesPerSecond){await ue(c.uploadCap?.knownBytes??0,c.uploadBytesPerSecond,y);V(y)}let d;if(q?.kind==="respond"){d=Se(p,q)}else{const E=M;M=true;let S;try{S=t(u,i)}finally{M=E}d=await S}if(c?.downloadBytesPerSecond){const E={};d.headers.forEach((x,N)=>{E[N.toLowerCase()]=x});let S=0;let X=0;const $=[];const G=(x,N)=>{const D=new Uint8Array(X);let se=0;for(const ne of $){D.set(ne,se);se+=ne.byteLength}let K=x?new TextDecoder().decode(D):Z;if(x&&E["content-type"]?.includes("json")){try{K=JSON.parse(K)}catch{}}e.emit({type:N!==void 0?"error":"response",timestamp:new Date,duration:v()-g,request:{id:f,url:L,method:n,headers:h,data:r,params:o||void 0,client:m},response:{status:d.status,statusText:d.statusText,headers:E,body:K,size:S},...N!==void 0?{error:{message:N instanceof Error?N.message:String(N)}}:{},override:O,condition:c})};G(false);return le(d,c.downloadBytesPerSecond,y,(x,N)=>{if(x){S+=x.byteLength;const D=Math.min(x.byteLength,65536-X);if(D>0){$.push(x.slice(0,D));X+=D}}else G(true,N)},n.toUpperCase()==="HEAD")}const _=v()-g;const F=typeof d.body?.getReader==="function"||de(d.headers?.get?.("content-type"));const I=d.clone();const{body:P,size:J}=F?{body:Z,size:0}:await e.processResponseBody(I);const U=v()-g;const z=Math.max(0,U-_);const j=z>0?{ttfb:_,download:z}:void 0;const T={};d.headers.forEach((E,S)=>{T[S.toLowerCase()]=E});e.emit({type:"response",timestamp:new Date,duration:U,timings:j,request:{id:f||"unknown",url:L,method:n,headers:h,data:r,params:o||void 0,client:m},response:{status:d.status,statusText:d.statusText,headers:T,body:P,size:J},override:O,condition:c});if(F){const E=d.headers?.get?.("content-type");void e.readStreamedBody(I,de(E)?void 0:1024*1024).then(S=>{let X=S.body;if(E?.includes("json")){try{X=JSON.parse(S.body)}catch{}}e.emit({type:"response",timestamp:new Date,duration:v()-g,timings:j,request:{id:f||"unknown",url:L,method:n,headers:h,data:r,params:o||void 0,client:m},response:{status:d.status,statusText:d.statusText,headers:T,body:X,size:S.size},override:O,condition:c})}).catch(()=>{})}return d}catch(d){const _=v()-g;e.emit({type:"error",timestamp:new Date,duration:_,request:{id:f||"unknown",url:L,method:n,headers:h,data:r,params:o||void 0,client:m},error:{message:d instanceof Error?d.message:"Network error",stack:d instanceof Error?d.stack:void 0},override:O,condition:c});throw d}};l[BUOY_FETCH_INTERCEPTOR_FLAG]=true;this.patchedFetch=l;globalThis.fetch=this.patchedFetch}installXhrInterceptor(){const e=this;const t=XMLHttpRequest.prototype.open;const s=XMLHttpRequest.prototype.send;const l=XMLHttpRequest.prototype.setRequestHeader;this.originalXHROpen=t;this.originalXHRSend=s;this.originalXHRSetRequestHeader=l;const u=++this.xhrGeneration;const i=new WeakMap;const p=function(a,n,y,R,c){const L=t.call(this,a,n,y??true,R,c);if(u===e.xhrGeneration){i.get(this)?.();const o=this;o._buoyRequestId=Y("xhr");o._method=a;o._url=W(n);o._buoyStartTime=v();o._requestHeaders={};o._buoyAsync=y!==false;o._buoyRestoreAbort?.();o._buoyWaitedForRules=false;o._buoyHeldSend=false;o._buoyOpenSeq=(o._buoyOpenSeq??0)+1}return L};const g=function(a,n){const y=this;if(u===e.xhrGeneration&&y._requestHeaders){y._requestHeaders[a]=n}return l.call(this,a,n)};const f=function(a){if(u!==e.xhrGeneration||M){return s.call(this,a)}if(He(this))throw new DOMException("The request has already been sent.","InvalidStateError");if(this.readyState!==1||this._sent){return s.call(this,a)}const n=this;if(n._buoyHeldSend)throw new DOMException("The request has already been sent.","InvalidStateError");if(!Re()&&n._buoyAsync!==false&&!n._buoyWaitedForRules){n._buoyWaitedForRules=true;n._buoyHeldSend=true;const T=n._buoyOpenSeq;let E=false;const S=Object.prototype.hasOwnProperty.call(this,"abort")?this.abort:void 0;const X=()=>{if(n._buoyRestoreAbort!==X)return;n._buoyRestoreAbort=void 0;if(S)this.abort=S;else delete this.abort};n._buoyRestoreAbort=X;const $=S??Object.getPrototypeOf(this).abort;this.abort=function(){E=true;n._buoyHeldSend=false;X();return $.call(this)};const G=()=>{X();if(E||n._buoyOpenSeq!==T)return;n._buoyHeldSend=false;if(this.readyState===1&&!this._sent)f.call(this,a)};void ie().then(G,G);return}const y=n._buoyRequestId;const R=n._method||"GET";const c=n._url||"";const L=v();n._buoyStartTime=L;n._buoyTtfb=void 0;const o=n._requestHeaders||{};Object.assign(o,ce(c));if(e.shouldIgnoreUrl(c)){return s.call(this,a)}const{url:h,params:H}=e.parseUrl(c);let r;if(a){if(typeof a==="string"){try{r=JSON.parse(a)}catch{r=a}}else{r=a}}const m=o["X-Request-Client"]||o["x-request-client"];const w=o["Accept"]||o["accept"]||"";const k=w.includes("application/json")&&w.includes("text/plain")&&w.includes("*/*")&&!ke();const q=m||(k?"axios":"xhr");const O=re(c);const B=O?.uploadBytesPerSecond?{...O,uploadCap:pe(a)}:O;const d=B?.profile==="offline"?null:oe(c,R,o,typeof a==="string"?a:void 0);const _=d?ae(d):void 0;e.emit({type:"request",timestamp:new Date,request:{id:y||"unknown",url:h,method:R,headers:o,data:r,params:H||void 0,client:q},override:_,condition:B});let F=false;const I=(T=false)=>{if(F)return;F=true;e.handleXHRResponse(this,y||"unknown",h,R,o,r,H,L||0,T,q,_,B);P()};const P=()=>{i.delete(this);this.removeEventListener("load",J);this.removeEventListener("error",U);this.removeEventListener("abort",z);this.removeEventListener("readystatechange",j)};i.set(this,P);const J=()=>{I(false)};const U=()=>{I(true)};const z=()=>{I(true)};const j=()=>{if(this.readyState===2){const T=this;if(T._buoyTtfb===void 0&&T._buoyStartTime){T._buoyTtfb=v()-T._buoyStartTime}}if(this.readyState===4&&!F){I(false)}};this.addEventListener("load",J);this.addEventListener("error",U);this.addEventListener("abort",z);this.addEventListener("readystatechange",j);if(B){me(this,c,B,d,()=>s.call(this,a),a);return}if(d){const T=Le(this,c,d,()=>s.call(this,a));if(T)return}return s.call(this,a)};f[BUOY_XHR_INTERCEPTOR_FLAG]=true;this.patchedXHROpen=p;this.patchedXHRSend=f;this.patchedXHRSetRequestHeader=g;XMLHttpRequest.prototype.open=this.patchedXHROpen;XMLHttpRequest.prototype.send=this.patchedXHRSend;XMLHttpRequest.prototype.setRequestHeader=this.patchedXHRSetRequestHeader}stopListening(){if(!this.isListening){return}this.fetchGeneration++;this.xhrGeneration++;if(this.patchedFetch&&globalThis.fetch===this.patchedFetch){globalThis.fetch=this.originalFetch}if(this.patchedXHROpen&&XMLHttpRequest.prototype.open===this.patchedXHROpen){XMLHttpRequest.prototype.open=this.originalXHROpen}if(this.patchedXHRSend&&XMLHttpRequest.prototype.send===this.patchedXHRSend){XMLHttpRequest.prototype.send=this.originalXHRSend}if(this.patchedXHRSetRequestHeader&&XMLHttpRequest.prototype.setRequestHeader===this.patchedXHRSetRequestHeader){XMLHttpRequest.prototype.setRequestHeader=this.originalXHRSetRequestHeader}this.patchedFetch=null;this.patchedXHROpen=null;this.patchedXHRSend=null;this.patchedXHRSetRequestHeader=null;this.isListening=false;if(__DEV__){}}adoptEarlyRequests(){const e=globalThis;const t=e[ve]??e.__BUOY_EARLY_NETWORK__;if(t?.version!==1)return;for(const s of t.adopt()){try{if(s.kind==="fetch")this.adoptEarlyFetch(s);else this.adoptEarlyXhr(s)}catch{}}}adoptEarlyFetch(e){const{input:t,init:s}=e;const l=typeof t==="object"&&"method"in t?t:void 0;const u=W(typeof t==="string"?t:t instanceof URL?t.href:t.url);if(this.shouldIgnoreUrl(u))return;const i=Y("fetch");const p=s?.method??l?.method??"GET";const{url:g,params:f}=this.parseUrl(u);const a=Oe(s?.headers??l?.headers);let n=s?.body;if(typeof n==="string"){try{n=JSON.parse(n)}catch{}}const y=a["X-Request-Client"]||a["x-request-client"]||"fetch";const R=()=>({id:i,url:g,method:p,headers:a,data:n,params:f||void 0,client:y});this.emit({type:"request",timestamp:new Date(e.start),request:R()});if(e.requestCopy){void this.readStreamedBody(e.requestCopy).then(({body:c})=>{try{n=JSON.parse(c)}catch{n=c}this.emit({type:"request-body",timestamp:new Date,request:{id:i,url:g,method:p,data:n,client:y}})}).catch(()=>{})}void e.settled.then(async({response:c,clone:L,error:o,headersAt:h})=>{if(!c){this.emit({type:"error",timestamp:new Date,duration:h-e.start,request:R(),error:{message:o instanceof Error?o.message:"Network error",stack:o instanceof Error?o.stack:void 0}});return}const{body:H,size:r}=L?await this.processResponseBody(L):{body:Z,size:0};const m=Math.max(0,v()-e.start);const w=h-e.start;const k={};c.headers.forEach((q,O)=>{k[O.toLowerCase()]=q});this.emit({type:"response",timestamp:new Date,duration:m,timings:m>w?{ttfb:w,download:m-w}:void 0,request:R(),response:{status:c.status,statusText:c.statusText,headers:k,body:H,size:r}})})}adoptEarlyXhr(e){const t=W(e.url);if(this.shouldIgnoreUrl(t))return;const s=Y("xhr");const l=e.method.toUpperCase();const{url:u,params:i}=this.parseUrl(t);let p=e.body;if(typeof p==="string"){try{p=JSON.parse(p)}catch{}}const g=e.headers["X-Request-Client"]||e.headers["x-request-client"]||"xhr";this.emit({type:"request",timestamp:new Date(e.start),request:{id:s,url:u,method:l,headers:e.headers,data:p,params:i||void 0,client:g}});const f=e.xhr;const a=()=>{const n=(f._buoyEarlyEnd??v())-e.start;this.handleXHRResponse(f,s,u,l,e.headers,p,i,v()-n,false,g)};if(f.readyState===4)a();else f.addEventListener("loadend",a,{once:true})}addListener(e){this.listeners.push(e);return()=>{const t=this.listeners.indexOf(e);if(t>-1){this.listeners.splice(t,1)}}}removeAllListeners(){this.listeners=[]}get isActive(){return this.isListening}get listenerCount(){return this.listeners.length}}let C=null;const te=()=>{if(!C){C=new Be}return C};export const networkListener=te;export const startNetworkListener=()=>te().startListening();export const stopNetworkListener=()=>C?.stopListening();export const addNetworkListener=b=>te().addListener(b);export const removeAllNetworkListeners=()=>C?.removeAllListeners();export const isNetworkListening=()=>C?.isActive??false;export const getNetworkListenerCount=()=>C?.listenerCount??0;export const isNetworkInterceptionLive=()=>C?.isInterceptionLive()??false;
|
|
@@ -46,6 +46,7 @@ export { networkSavedStore, flagsForEventId, FREE_TIER_SAVED_LIMIT, MAX_PINNED,
|
|
|
46
46
|
export { generateCurl } from "./network/utils/generateCurl";
|
|
47
47
|
/** @internal */
|
|
48
48
|
export { networkListener, addNetworkListener, removeAllNetworkListeners, } from "./network/utils/networkListener";
|
|
49
|
-
export { NETWORK_CONDITIONS, getNetworkCondition, setNetworkCondition, subscribeNetworkConditions } from "./network/conditions/store";
|
|
50
|
-
export type { NetworkConditionProfile, NetworkConditionStamp } from "./network/conditions/store";
|
|
49
|
+
export { NETWORK_CONDITIONS, getNetworkCondition, setNetworkCondition, subscribeNetworkConditions, getNetworkConditions, setNetworkConditions, getNetworkConnection, getConditionsRevision, networkConditionsActive } from "./network/conditions/store";
|
|
50
|
+
export type { NetworkConditionProfile, NetworkConditionStamp, NetworkConditionsState, NetworkConditionsChange, NetworkConnection } from "./network/conditions/store";
|
|
51
|
+
export { chooseConditionsSnapshot } from "./network/conditions/remoteState";
|
|
51
52
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -53,6 +53,7 @@ export { filterNetworkEvents, applyIgnoredPatterns, } from "./network/utils/filt
|
|
|
53
53
|
export { splitPinned, type PinnedSplit } from "./network/utils/withPinnedFirst";
|
|
54
54
|
export { extractOperationName } from "./network/utils/extractOperationName";
|
|
55
55
|
export { generateCurl } from "./network/utils/generateCurl";
|
|
56
|
-
export { NETWORK_CONDITIONS, getNetworkCondition, setNetworkCondition, subscribeNetworkConditions } from "./network/conditions/store";
|
|
57
|
-
export type { NetworkConditionProfile, NetworkConditionStamp } from "./network/conditions/store";
|
|
56
|
+
export { NETWORK_CONDITIONS, getNetworkCondition, setNetworkCondition, subscribeNetworkConditions, getNetworkConditions, setNetworkConditions, getNetworkConnection, getConditionsRevision, networkConditionsActive } from "./network/conditions/store";
|
|
57
|
+
export type { NetworkConditionProfile, NetworkConditionStamp, NetworkConditionsState, NetworkConditionsChange, NetworkConnection } from "./network/conditions/store";
|
|
58
|
+
export { chooseConditionsSnapshot } from "./network/conditions/remoteState";
|
|
58
59
|
//# sourceMappingURL=index.web.d.ts.map
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { type NetworkConditionProfile } from "./store";
|
|
1
|
+
import { type NetworkConditionProfile, type NetworkConditionsState, type NetworkConnection } from "./store";
|
|
2
2
|
export interface RemoteNetworkConditions {
|
|
3
3
|
/** Identity of the connected device session, used to ignore stale UI completions. */
|
|
4
4
|
targetId?: string;
|
|
5
5
|
profile: NetworkConditionProfile | null;
|
|
6
|
+
state?: NetworkConditionsState;
|
|
7
|
+
onConnectionChange?(connection: NetworkConnection): Promise<unknown>;
|
|
6
8
|
available: boolean;
|
|
7
9
|
onChange(profile: NetworkConditionProfile): Promise<unknown>;
|
|
8
10
|
}
|
|
9
|
-
export declare function NetworkConditionsControl({ remote }: {
|
|
11
|
+
export declare function NetworkConditionsControl({ remote, compact }: {
|
|
10
12
|
remote?: RemoteNetworkConditions;
|
|
13
|
+
compact?: boolean;
|
|
11
14
|
}): import("react").JSX.Element;
|
|
12
15
|
//# sourceMappingURL=NetworkConditionsControl.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FloatingToolRenderContext } from "@buoy-gg/shared-ui";
|
|
2
|
-
import type
|
|
2
|
+
import { type RemoteNetworkConditions } from "./NetworkConditionsControl";
|
|
3
3
|
/** A live source keeps the desktop strip current after its launching panel closes. */
|
|
4
4
|
export declare function createRemoteConditionsSource(): {
|
|
5
5
|
getSnapshot: () => RemoteNetworkConditions | undefined;
|
|
@@ -8,9 +8,10 @@ export declare function createRemoteConditionsSource(): {
|
|
|
8
8
|
};
|
|
9
9
|
type RemoteSource = ReturnType<typeof createRemoteConditionsSource>;
|
|
10
10
|
export declare function registerLocalNetworkFloatingTool(): () => void;
|
|
11
|
-
export declare function openNetworkFloatingTool(source?: RemoteSource): void;
|
|
12
|
-
export declare function NetworkFloatingTool({ id, revealToken, dismiss, source }: FloatingToolRenderContext & {
|
|
11
|
+
export declare function openNetworkFloatingTool(source?: RemoteSource, showControls?: boolean): void;
|
|
12
|
+
export declare function NetworkFloatingTool({ id, revealToken, dismiss, source, showControls }: FloatingToolRenderContext & {
|
|
13
13
|
source?: RemoteSource;
|
|
14
|
+
showControls?: boolean;
|
|
14
15
|
}): import("react").JSX.Element;
|
|
15
16
|
export {};
|
|
16
17
|
//# sourceMappingURL=NetworkFloatingTool.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { NetworkConnection } from "../profiles";
|
|
2
|
+
export interface ConnectionState {
|
|
3
|
+
type?: string;
|
|
4
|
+
details?: unknown;
|
|
5
|
+
isConnected?: boolean | null;
|
|
6
|
+
isInternetReachable?: boolean | null;
|
|
7
|
+
}
|
|
8
|
+
export interface ConnectivityModule {
|
|
9
|
+
getCurrentState(requestedInterface?: string): Promise<ConnectionState>;
|
|
10
|
+
eventEmitter: {
|
|
11
|
+
addListener(event: string, listener: (state: ConnectionState) => void): {
|
|
12
|
+
remove(): void;
|
|
13
|
+
};
|
|
14
|
+
listenerCount?(event: string): number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function maskConnection(state: ConnectionState, mode: NetworkConnection, expo?: boolean): ConnectionState;
|
|
18
|
+
/** Install before the library creates any state managers or app listeners. */
|
|
19
|
+
export declare function patchConnectionState(native: ConnectivityModule, mode: () => NetworkConnection, subscribe: (listener: () => void) => () => void, options?: {
|
|
20
|
+
eventName?: string;
|
|
21
|
+
expo?: boolean;
|
|
22
|
+
receiver?: object;
|
|
23
|
+
}): () => void;
|
|
24
|
+
//# sourceMappingURL=patchNetwork.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UploadCap } from "./profiles";
|
|
2
|
+
export declare const chunkSize: (rate: number) => number;
|
|
3
|
+
export declare const utf8Length: (text: string) => number;
|
|
4
|
+
/** Returns null when the native encoder owns a body whose byte size is unknown. */
|
|
5
|
+
export declare function bodyByteLength(body: unknown): number | null;
|
|
6
|
+
/** The upload is a pre-send simulation. No bytes are sent during these ticks. */
|
|
7
|
+
export declare function paceByteCount(bytes: number, rate: number, signal?: AbortSignal | null, progress?: (loaded: number, total: number) => void): Promise<void>;
|
|
8
|
+
export declare function uploadBodySize(input: RequestInfo | URL, init?: RequestInit): UploadCap;
|
|
9
|
+
/** Inspect sizes only. Never read a stream, open a URI, or alter the body. */
|
|
10
|
+
export declare function uploadSize(body: unknown): UploadCap;
|
|
11
|
+
/** Carry timer overshoot forward, but never bank idle time between reads. */
|
|
12
|
+
export declare function createBytePacer(rate: number): (bytes: number, signal?: AbortSignal | null) => Promise<void>;
|
|
13
|
+
export declare function pacedStream(source: ReadableStream<Uint8Array>, rate: number, signal?: AbortSignal | null, observe?: (chunk: Uint8Array | null, error?: unknown) => void): ReadableStream<Uint8Array<ArrayBufferLike>>;
|
|
14
|
+
/** Wrap body delivery without assuming RN's Response constructor accepts streams. */
|
|
15
|
+
export declare function paceResponse(response: Response, rate: number, signal?: AbortSignal | null, observe?: (chunk: Uint8Array | null, error?: unknown) => void, noBody?: boolean): Response;
|
|
16
|
+
//# sourceMappingURL=pacer.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare const NETWORK_CONDITIONS: {
|
|
2
|
+
readonly normal: {
|
|
3
|
+
readonly label: "Normal";
|
|
4
|
+
readonly delayMs: 0;
|
|
5
|
+
};
|
|
6
|
+
readonly offline: {
|
|
7
|
+
readonly label: "Offline (requests)";
|
|
8
|
+
readonly delayMs: 0;
|
|
9
|
+
};
|
|
10
|
+
readonly slow: {
|
|
11
|
+
readonly label: "Slow (+500 ms)";
|
|
12
|
+
readonly delayMs: 500;
|
|
13
|
+
};
|
|
14
|
+
readonly verySlow: {
|
|
15
|
+
readonly label: "Very slow (+2000 ms)";
|
|
16
|
+
readonly delayMs: 2000;
|
|
17
|
+
};
|
|
18
|
+
readonly slow3g: {
|
|
19
|
+
readonly label: "Slow 3G";
|
|
20
|
+
readonly delayMs: 2000;
|
|
21
|
+
readonly downloadBytesPerSecond: 50000;
|
|
22
|
+
readonly uploadBytesPerSecond: 50000;
|
|
23
|
+
};
|
|
24
|
+
readonly slow4g: {
|
|
25
|
+
readonly label: "Slow 4G";
|
|
26
|
+
readonly delayMs: 562.5;
|
|
27
|
+
readonly downloadBytesPerSecond: 180000;
|
|
28
|
+
readonly uploadBytesPerSecond: 84375;
|
|
29
|
+
};
|
|
30
|
+
readonly fast4g: {
|
|
31
|
+
readonly label: "Fast 4G";
|
|
32
|
+
readonly delayMs: 165;
|
|
33
|
+
readonly downloadBytesPerSecond: 1012500;
|
|
34
|
+
readonly uploadBytesPerSecond: 168750;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export type NetworkConditionProfile = keyof typeof NETWORK_CONDITIONS;
|
|
38
|
+
export type NetworkConnection = "auto" | "real" | "offline" | "wifi" | "cellular" | "noInternet";
|
|
39
|
+
export declare const CONNECTIONS: NetworkConnection[];
|
|
40
|
+
export interface NetworkConditionStamp {
|
|
41
|
+
readonly profile: NetworkConditionProfile;
|
|
42
|
+
readonly delayMs: number;
|
|
43
|
+
readonly downloadBytesPerSecond?: number;
|
|
44
|
+
readonly uploadBytesPerSecond?: number;
|
|
45
|
+
readonly uploadCap?: UploadCap;
|
|
46
|
+
}
|
|
47
|
+
export interface UploadCap {
|
|
48
|
+
readonly knownBytes: number;
|
|
49
|
+
readonly status: "applied" | "partial" | "not-applied";
|
|
50
|
+
readonly note?: string;
|
|
51
|
+
}
|
|
52
|
+
export declare const CONDITIONS_SCOPE: {
|
|
53
|
+
download: string;
|
|
54
|
+
upload: string;
|
|
55
|
+
transports: string;
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { NetworkConditionsState } from "./store";
|
|
2
|
+
/** A new runtime needs a fresh read; old snapshots cannot rearm its controls. */
|
|
3
|
+
export declare function chooseConditionsSnapshot(confirmed: NetworkConditionsState | null, snapshot?: NetworkConditionsState): NetworkConditionsState | null;
|
|
4
|
+
//# sourceMappingURL=remoteState.d.ts.map
|
|
@@ -1,26 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { type NetworkConditionProfile, type NetworkConnection, type NetworkConditionStamp } from "./profiles";
|
|
2
|
+
export { NETWORK_CONDITIONS, CONDITIONS_SCOPE } from "./profiles";
|
|
3
|
+
export type { NetworkConditionProfile, NetworkConnection, NetworkConditionStamp } from "./profiles";
|
|
4
|
+
export interface ConnectionSupport {
|
|
5
|
+
supported: boolean;
|
|
6
|
+
reason?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const connectionSupport: {
|
|
9
|
+
netInfo: ConnectionSupport;
|
|
10
|
+
expoNetwork: ConnectionSupport;
|
|
11
|
+
};
|
|
12
|
+
export declare const getNetworkConnection: () => NetworkConnection;
|
|
13
|
+
export declare const getConditionsRevision: () => number;
|
|
14
|
+
export declare const getEffectiveNetworkConnection: () => "real" | "offline" | "wifi" | "cellular" | "noInternet";
|
|
15
|
+
export declare const networkConditionsActive: () => boolean;
|
|
16
|
+
export declare function setConnectionSupport(key: keyof typeof connectionSupport, value: ConnectionSupport): void;
|
|
17
|
+
export declare function getNetworkConditions(): {
|
|
18
|
+
version: 2;
|
|
19
|
+
runtimeId: string;
|
|
20
|
+
revision: number;
|
|
21
|
+
profile: "offline" | "normal" | "slow" | "verySlow" | "slow3g" | "slow4g" | "fast4g";
|
|
22
|
+
connection: NetworkConnection;
|
|
23
|
+
available: boolean;
|
|
24
|
+
active: boolean;
|
|
25
|
+
delayMs: number;
|
|
26
|
+
downloadBytesPerSecond: number | null;
|
|
27
|
+
uploadBytesPerSecond: number | null;
|
|
28
|
+
capabilities: {
|
|
29
|
+
fetch: string;
|
|
30
|
+
xhr: string;
|
|
31
|
+
upload: string;
|
|
32
|
+
webSocket: boolean;
|
|
33
|
+
nativeImages: boolean;
|
|
34
|
+
nativeModules: boolean;
|
|
35
|
+
netInfo: ConnectionSupport;
|
|
36
|
+
expoNetwork: ConnectionSupport;
|
|
13
37
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
38
|
+
scope: {
|
|
39
|
+
download: string;
|
|
40
|
+
upload: string;
|
|
41
|
+
transports: string;
|
|
17
42
|
};
|
|
18
43
|
};
|
|
19
|
-
export type
|
|
20
|
-
export interface
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
export type NetworkConditionsState = ReturnType<typeof getNetworkConditions>;
|
|
45
|
+
export interface NetworkConditionsChange {
|
|
46
|
+
profile?: NetworkConditionProfile;
|
|
47
|
+
connection?: NetworkConnection;
|
|
23
48
|
}
|
|
49
|
+
export declare function setNetworkConditions(value?: unknown): NetworkConditionsState;
|
|
24
50
|
export declare const networkConditionsRuntimeId: string;
|
|
25
51
|
export declare const conditionsCanApply: () => boolean;
|
|
26
52
|
export declare const getNetworkCondition: () => NetworkConditionProfile;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OverrideOutcome } from "../overrides/types";
|
|
2
2
|
import type { NetworkConditionStamp } from "./store";
|
|
3
3
|
/** Active simulation uses a send-to-completion deadline, including the wait. */
|
|
4
|
-
export declare function runConditionXhr(target: XMLHttpRequest, url: string, condition: NetworkConditionStamp, outcome: OverrideOutcome | null, dispatch: () => void): void;
|
|
4
|
+
export declare function runConditionXhr(target: XMLHttpRequest, url: string, condition: NetworkConditionStamp, outcome: OverrideOutcome | null, dispatch: () => void, body?: unknown): void;
|
|
5
5
|
//# sourceMappingURL=xhr.d.ts.map
|
|
@@ -3,6 +3,10 @@ export interface OverrideHooks {
|
|
|
3
3
|
getRules: () => readonly OverrideRule[];
|
|
4
4
|
/** The rule APPLIED to a request. */
|
|
5
5
|
recordHit: (ruleId: string) => void;
|
|
6
|
+
/** Resolves once saved rules are loaded (a request at app start waits for it). */
|
|
7
|
+
ready?: () => Promise<void>;
|
|
8
|
+
/** True once saved rules are loaded, for callers that can't wait on a promise first. */
|
|
9
|
+
isReady?: () => boolean;
|
|
6
10
|
/**
|
|
7
11
|
* The rule MATCHED a request, whether or not it applied.
|
|
8
12
|
*
|
|
@@ -12,6 +16,16 @@ export interface OverrideHooks {
|
|
|
12
16
|
recordMatch: (ruleId: string) => void;
|
|
13
17
|
}
|
|
14
18
|
export declare function setOverrideHooks(next: OverrideHooks | null): void;
|
|
19
|
+
/**
|
|
20
|
+
* Wait for saved rules before an async request decides. At app start the
|
|
21
|
+
* rules are still loading; a loaded bug case's sandbox would otherwise miss
|
|
22
|
+
* the app's first calls and let them reach real servers.
|
|
23
|
+
*/
|
|
24
|
+
export declare function overrideRulesReady(): Promise<void>;
|
|
25
|
+
/** Whether saved rules are loaded yet. */
|
|
26
|
+
export declare function overrideRulesLoaded(): boolean;
|
|
27
|
+
/** Whether any rule reads the request body (a body match or a GraphQL operation). */
|
|
28
|
+
export declare function overrideRulesNeedBody(): boolean;
|
|
15
29
|
/**
|
|
16
30
|
* Whether a rule stored right now could ever be applied to a request.
|
|
17
31
|
*
|
|
@@ -17,6 +17,9 @@ import type { OverrideRule } from "./types";
|
|
|
17
17
|
*/
|
|
18
18
|
export declare function escapeRegex(pattern: string): string;
|
|
19
19
|
export declare function compilePattern(pattern: string): RegExp;
|
|
20
|
+
/** A GraphQL JSON body (one operation or a batch) that names `operation`. */
|
|
21
|
+
/** JSON with object keys sorted at every level, so equal values give equal text. */
|
|
22
|
+
export declare function canonicalJson(value: unknown): string;
|
|
20
23
|
/** Does this rule apply to this request? Ignores `enabled` — callers check it. */
|
|
21
24
|
export declare function ruleMatches(rule: OverrideRule, url: string, method: string, headers?: Record<string, string>, body?: string): boolean;
|
|
22
25
|
//# sourceMappingURL=matchRule.d.ts.map
|
|
@@ -111,6 +111,8 @@ declare class OverrideRulesStore {
|
|
|
111
111
|
* needs no second check.
|
|
112
112
|
*/
|
|
113
113
|
getRules(): readonly OverrideRule[];
|
|
114
|
+
private sandboxCache;
|
|
115
|
+
private sandboxOnly;
|
|
114
116
|
/**
|
|
115
117
|
* The rule's real body, fetching it from the device when this surface only
|
|
116
118
|
* has the stripped copy (see `OverrideRule.bodyOmitted`).
|
|
@@ -172,6 +174,7 @@ declare class OverrideRulesStore {
|
|
|
172
174
|
* because a rule has to fire from app boot — with the Network tool closed and
|
|
173
175
|
* nothing capturing. On the web `loadNow` has usually done it already.
|
|
174
176
|
*/
|
|
177
|
+
isLoaded(): boolean;
|
|
175
178
|
ensureLoaded(): Promise<void>;
|
|
176
179
|
/**
|
|
177
180
|
* Web only: read the saved rules from localStorage right now.
|
|
@@ -89,6 +89,25 @@ export interface OverrideRule {
|
|
|
89
89
|
* asked first. A body that isn't text (FormData, a Blob) never matches.
|
|
90
90
|
*/
|
|
91
91
|
bodyIncludes?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Only GraphQL requests whose JSON body names this `operationName` (or a
|
|
94
|
+
* batch that holds it). Parsed, not matched as text, so spacing and key
|
|
95
|
+
* order in the body don't matter.
|
|
96
|
+
*/
|
|
97
|
+
graphqlOperation?: string;
|
|
98
|
+
/**
|
|
99
|
+
* With graphqlOperation: only when that operation's `variables` equal this,
|
|
100
|
+
* written as JSON with its keys sorted (see canonicalJson). Parsed, so
|
|
101
|
+
* spacing and key order don't matter. Missing variables count as {}.
|
|
102
|
+
*/
|
|
103
|
+
graphqlVariables?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Part of a loaded bug case's sandbox (bug links). Such a rule keeps
|
|
106
|
+
* applying while Buoy's account access is off, because the case's data is
|
|
107
|
+
* in the app either way and must not reach a real server, and it is never
|
|
108
|
+
* auto-paused at launch. Release builds still never apply any rule.
|
|
109
|
+
*/
|
|
110
|
+
sandbox?: boolean;
|
|
92
111
|
kind: OverrideRuleKind;
|
|
93
112
|
/** `respond` only. Clamped to [STATUS_MIN, STATUS_MAX]. Defaults to 200. */
|
|
94
113
|
status?: number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getNetworkConditions, setNetworkConditions } from "../conditions/store";
|
|
1
2
|
import type { OverrideRulesState } from "../overrides/overrideRulesStore";
|
|
2
3
|
import { type OverrideRuleKind } from "../overrides/types";
|
|
3
4
|
import type { NetworkEvent } from "../types";
|
|
@@ -54,10 +55,31 @@ export declare const networkSyncAdapter: {
|
|
|
54
55
|
version: number;
|
|
55
56
|
getSnapshot: () => {
|
|
56
57
|
conditions: {
|
|
57
|
-
version:
|
|
58
|
+
version: 2;
|
|
58
59
|
runtimeId: string;
|
|
59
|
-
|
|
60
|
+
revision: number;
|
|
61
|
+
profile: "offline" | "normal" | "slow" | "verySlow" | "slow3g" | "slow4g" | "fast4g";
|
|
62
|
+
connection: import("../..").NetworkConnection;
|
|
60
63
|
available: boolean;
|
|
64
|
+
active: boolean;
|
|
65
|
+
delayMs: number;
|
|
66
|
+
downloadBytesPerSecond: number | null;
|
|
67
|
+
uploadBytesPerSecond: number | null;
|
|
68
|
+
capabilities: {
|
|
69
|
+
fetch: string;
|
|
70
|
+
xhr: string;
|
|
71
|
+
upload: string;
|
|
72
|
+
webSocket: boolean;
|
|
73
|
+
nativeImages: boolean;
|
|
74
|
+
nativeModules: boolean;
|
|
75
|
+
netInfo: import("../conditions/store").ConnectionSupport;
|
|
76
|
+
expoNetwork: import("../conditions/store").ConnectionSupport;
|
|
77
|
+
};
|
|
78
|
+
scope: {
|
|
79
|
+
download: string;
|
|
80
|
+
upload: string;
|
|
81
|
+
transports: string;
|
|
82
|
+
};
|
|
61
83
|
};
|
|
62
84
|
events: NetworkEvent[];
|
|
63
85
|
/**
|
|
@@ -79,16 +101,8 @@ export declare const networkSyncAdapter: {
|
|
|
79
101
|
};
|
|
80
102
|
subscribe: (onChange: () => void) => () => void;
|
|
81
103
|
actions: {
|
|
82
|
-
getNetworkConditions:
|
|
83
|
-
|
|
84
|
-
profile: "normal" | "offline" | "slow" | "verySlow";
|
|
85
|
-
available: boolean;
|
|
86
|
-
};
|
|
87
|
-
setNetworkConditions: (params?: unknown) => {
|
|
88
|
-
runtimeId: string;
|
|
89
|
-
profile: "normal" | "offline" | "slow" | "verySlow";
|
|
90
|
-
available: boolean;
|
|
91
|
-
};
|
|
104
|
+
getNetworkConditions: typeof getNetworkConditions;
|
|
105
|
+
setNetworkConditions: typeof setNetworkConditions;
|
|
92
106
|
clearEvents: () => void;
|
|
93
107
|
/**
|
|
94
108
|
* Return the full (un-stripped) request/response bodies for one event,
|
|
@@ -101,6 +115,7 @@ export declare const networkSyncAdapter: {
|
|
|
101
115
|
method: string;
|
|
102
116
|
status: number | null;
|
|
103
117
|
override: import("../types").NetworkOverrideMark | null;
|
|
118
|
+
condition: import("../..").NetworkConditionStamp | null;
|
|
104
119
|
requestData: {} | null;
|
|
105
120
|
responseData: {} | null;
|
|
106
121
|
requestHeaders: Record<string, string>;
|
|
@@ -170,6 +170,10 @@ declare class NetworkListener {
|
|
|
170
170
|
* in flight are emitted when they finish. The recorder stops recording on
|
|
171
171
|
* the first call, so each request is reported once. See
|
|
172
172
|
* core/src/earlyNetwork.ts for the record shapes.
|
|
173
|
+
*
|
|
174
|
+
* The recorder sits on a hidden `Symbol.for("buoy.earlyNetwork")` key. An
|
|
175
|
+
* older core only sets `__BUOY_EARLY_NETWORK__`, so that name is read as a
|
|
176
|
+
* fallback. Drop the fallback once no supported core writes only that name.
|
|
173
177
|
*/
|
|
174
178
|
adoptEarlyRequests(): void;
|
|
175
179
|
private adoptEarlyFetch;
|