@buoy-gg/network 7.0.13 → 7.0.15
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/lib/commonjs/index.js +39 -0
- package/lib/commonjs/network/components/NetworkEventDetailView.js +30 -3
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +4 -0
- package/lib/commonjs/network/components/NetworkHeaderLive.js +26 -6
- package/lib/commonjs/network/components/NetworkHeaderMenu.js +183 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +126 -5
- package/lib/commonjs/network/components/NetworkModal.js +136 -29
- package/lib/commonjs/network/components/NetworkNumberPrompt.js +178 -0
- package/lib/commonjs/network/components/NetworkOverrideEditor.js +797 -0
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +102 -0
- package/lib/commonjs/network/components/NetworkOverridesButton.js +88 -0
- package/lib/commonjs/network/components/NetworkOverridesScreen.js +489 -0
- package/lib/commonjs/network/components/response-editor/Explorer.js +973 -0
- package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +56 -0
- package/lib/commonjs/network/components/response-editor/editorContext.js +33 -0
- package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +61 -0
- package/lib/commonjs/network/hooks/useOverrideRules.js +36 -0
- package/lib/commonjs/network/overrides/applyToFetch.js +80 -0
- package/lib/commonjs/network/overrides/applyToXhr.js +190 -0
- package/lib/commonjs/network/overrides/engine.js +70 -0
- package/lib/commonjs/network/overrides/matchRule.js +81 -0
- package/lib/commonjs/network/overrides/overrideRulesStore.js +550 -0
- package/lib/commonjs/network/overrides/presets.js +70 -0
- package/lib/commonjs/network/overrides/resolveOverride.js +158 -0
- package/lib/commonjs/network/overrides/types.js +85 -0
- package/lib/commonjs/network/sync/networkSyncAdapter.js +230 -1
- package/lib/commonjs/network/types/index.js +5 -1
- package/lib/commonjs/network/utils/networkEventStore.js +52 -6
- package/lib/commonjs/network/utils/networkListener.js +90 -10
- package/lib/commonjs/preset.js +11 -0
- package/lib/module/index.js +15 -0
- package/lib/module/network/components/NetworkEventDetailView.js +31 -4
- package/lib/module/network/components/NetworkEventItemCompact.js +5 -1
- package/lib/module/network/components/NetworkHeaderLive.js +26 -6
- package/lib/module/network/components/NetworkHeaderMenu.js +177 -0
- package/lib/module/network/components/NetworkListScreen.js +127 -6
- package/lib/module/network/components/NetworkModal.js +138 -31
- package/lib/module/network/components/NetworkNumberPrompt.js +174 -0
- package/lib/module/network/components/NetworkOverrideEditor.js +794 -0
- package/lib/module/network/components/NetworkOverrideHeaderButton.js +99 -0
- package/lib/module/network/components/NetworkOverridesButton.js +85 -0
- package/lib/module/network/components/NetworkOverridesScreen.js +485 -0
- package/lib/module/network/components/response-editor/Explorer.js +972 -0
- package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +51 -0
- package/lib/module/network/components/response-editor/editorContext.js +29 -0
- package/lib/module/network/components/response-editor/updateNestedDataByPath.js +56 -0
- package/lib/module/network/hooks/useOverrideRules.js +32 -0
- package/lib/module/network/overrides/applyToFetch.js +72 -0
- package/lib/module/network/overrides/applyToXhr.js +185 -0
- package/lib/module/network/overrides/engine.js +64 -0
- package/lib/module/network/overrides/matchRule.js +75 -0
- package/lib/module/network/overrides/overrideRulesStore.js +547 -0
- package/lib/module/network/overrides/presets.js +65 -0
- package/lib/module/network/overrides/resolveOverride.js +152 -0
- package/lib/module/network/overrides/types.js +80 -0
- package/lib/module/network/sync/networkSyncAdapter.js +230 -1
- package/lib/module/network/types/index.js +3 -1
- package/lib/module/network/utils/networkEventStore.js +52 -6
- package/lib/module/network/utils/networkListener.js +91 -10
- package/lib/module/preset.js +13 -1
- package/lib/typescript/index.d.ts +8 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +6 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts +8 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts +46 -0
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts +33 -0
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts +27 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +29 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts +17 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts +9 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts +29 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts +10 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts +29 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts +16 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts +19 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts +22 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts +50 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts +43 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -0
- package/lib/typescript/network/overrides/engine.d.ts +47 -0
- package/lib/typescript/network/overrides/engine.d.ts.map +1 -0
- package/lib/typescript/network/overrides/matchRule.d.ts +22 -0
- package/lib/typescript/network/overrides/matchRule.d.ts.map +1 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts +205 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +1 -0
- package/lib/typescript/network/overrides/presets.d.ts +38 -0
- package/lib/typescript/network/overrides/presets.d.ts.map +1 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts +46 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts.map +1 -0
- package/lib/typescript/network/overrides/types.d.ts +169 -0
- package/lib/typescript/network/overrides/types.d.ts.map +1 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts +73 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/network/types/index.d.ts +10 -0
- package/lib/typescript/network/types/index.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkEventStore.d.ts +14 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkListener.d.ts +3 -0
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
- package/lib/typescript/preset.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type OverrideRuleDraft, type OverrideRulesState } from "../overrides/overrideRulesStore";
|
|
2
|
+
import type { OverrideRule } from "../overrides/types";
|
|
3
|
+
export interface UseOverrideRulesResult extends OverrideRulesState {
|
|
4
|
+
/** Rules that would actually fire — what the "active" banner counts. */
|
|
5
|
+
activeCount: number;
|
|
6
|
+
setEnabled: (enabled: boolean) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Create or replace a rule. The ONLY write path the UI uses — see
|
|
9
|
+
* `overrideRulesStore.upsertRule`: the add/update primitives don't forward to
|
|
10
|
+
* the device, so calling them from the dashboard would silently do nothing.
|
|
11
|
+
*/
|
|
12
|
+
upsertRule: (draft: OverrideRuleDraft & {
|
|
13
|
+
id?: string;
|
|
14
|
+
}) => OverrideRule | null;
|
|
15
|
+
setRuleEnabled: (id: string, enabled: boolean) => void;
|
|
16
|
+
removeRule: (id: string) => void;
|
|
17
|
+
clearRules: () => void;
|
|
18
|
+
/** Has this rule burned through its `times` budget? */
|
|
19
|
+
isRuleSpent: (rule: OverrideRule) => boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read + mutate the override rule list.
|
|
23
|
+
*
|
|
24
|
+
* `useSyncExternalStore` over the store's own subscribe/getState, which already
|
|
25
|
+
* hands out a stable state object per mutation (see `rebuild`) — so this can't
|
|
26
|
+
* tear and doesn't need a selector to stay cheap.
|
|
27
|
+
*/
|
|
28
|
+
export declare function useOverrideRules(): UseOverrideRulesResult;
|
|
29
|
+
//# sourceMappingURL=useOverrideRules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOverrideRules.d.ts","sourceRoot":"","sources":["../../../../src/network/hooks/useOverrideRules.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,iBAAiB,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,YAAY,GAAG,IAAI,CAAC;IAChF,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvD,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,uDAAuD;IACvD,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,sBAAsB,CAsCzD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the fetch-side synthesis.
|
|
3
|
+
*
|
|
4
|
+
* This layer exists because of a finding that only showed up on a real device:
|
|
5
|
+
* Expo replaces `globalThis.fetch` with a NATIVE `expo/fetch` (see
|
|
6
|
+
* `expo/src/winter/runtime.native.ts`), so those requests never construct an
|
|
7
|
+
* XMLHttpRequest and an XHR-only override silently does nothing. Verified on
|
|
8
|
+
* Expo SDK 56 / RN 0.85.3.
|
|
9
|
+
*
|
|
10
|
+
* Same self-contained harness as the other tests — see the run command in
|
|
11
|
+
* `resolveOverride.test.ts`. Excluded from the publish build by
|
|
12
|
+
* `tsconfig.build.json`.
|
|
13
|
+
*/
|
|
14
|
+
declare function main(): Promise<void>;
|
|
15
|
+
export { main as runApplyToFetchTests };
|
|
16
|
+
//# sourceMappingURL=applyToFetch.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyToFetch.test.d.ts","sourceRoot":"","sources":["../../../../../src/network/overrides/__tests__/applyToFetch.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA2KH,iBAAe,IAAI,kBAsBlB;AAaD,OAAO,EAAE,IAAI,IAAI,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the XHR response synthesis, against a faithful clone of React
|
|
3
|
+
* Native's XMLHttpRequest state machine.
|
|
4
|
+
*
|
|
5
|
+
* WHY A CLONE RATHER THAN A MOCK: the interesting behaviour is not "did we set
|
|
6
|
+
* some fields", it's whether RN's own `setReadyState` / `abort` branches then
|
|
7
|
+
* do the right thing — which terminal event fires, and what `abort()` does when
|
|
8
|
+
* `_sent` is or isn't claimed. A mock that just records calls would pass while
|
|
9
|
+
* the real thing hung the app's fetch promise. `FakeRNXhr` below is transcribed
|
|
10
|
+
* from `react-native/Libraries/Network/XMLHttpRequest.js` (verified identical on
|
|
11
|
+
* RN 0.81.4 and 0.85.3), so these assertions are about real semantics.
|
|
12
|
+
*
|
|
13
|
+
* Same self-contained harness as the other tests — see the run command in
|
|
14
|
+
* `resolveOverride.test.ts`. Excluded from the publish build by
|
|
15
|
+
* `tsconfig.build.json`.
|
|
16
|
+
*/
|
|
17
|
+
declare function main(): Promise<void>;
|
|
18
|
+
export { main as runApplyToXhrTests };
|
|
19
|
+
//# sourceMappingURL=applyToXhr.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyToXhr.test.d.ts","sourceRoot":"","sources":["../../../../../src/network/overrides/__tests__/applyToXhr.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAqYH,iBAAe,IAAI,kBAuBlB;AAaD,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the override matcher + resolver — the pure half of the
|
|
3
|
+
* feature, and the half worth testing without a device.
|
|
4
|
+
*
|
|
5
|
+
* The glob cases mirror Chrome DevTools' own `escapeRegex` behaviour
|
|
6
|
+
* (`NetworkPersistenceManager.ts:1051`), because these patterns are the same
|
|
7
|
+
* syntax a developer already uses in Chrome's "Override headers" `applyTo`
|
|
8
|
+
* field and must not quietly mean something different here.
|
|
9
|
+
*
|
|
10
|
+
* Same self-contained harness as the perf-monitor tests (no Jest wired up yet);
|
|
11
|
+
* renames to Jest globals later. There is no `tsx` in this repo, so run it with
|
|
12
|
+
* the esbuild that is already here, from the repo root:
|
|
13
|
+
*
|
|
14
|
+
* node_modules/.bin/esbuild <this file> --bundle --platform=node \
|
|
15
|
+
* --format=cjs --outfile=/tmp/t.cjs && node /tmp/t.cjs
|
|
16
|
+
*
|
|
17
|
+
* `__tests__` is excluded from the publish build via `tsconfig.build.json`,
|
|
18
|
+
* so this file ships nowhere — it's developer infrastructure.
|
|
19
|
+
*/
|
|
20
|
+
declare function main(): Promise<void>;
|
|
21
|
+
export { main as runResolveOverrideTests };
|
|
22
|
+
//# sourceMappingURL=resolveOverride.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveOverride.test.d.ts","sourceRoot":"","sources":["../../../../../src/network/overrides/__tests__/resolveOverride.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA0XH,iBAAe,IAAI,kBAuBlB;AAeD,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perform an override outcome against `fetch`.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS — and why "XHR is the single choke point" is WRONG:
|
|
5
|
+
*
|
|
6
|
+
* In bare React Native, `Libraries/Network/fetch.js` is `require('whatwg-fetch')`,
|
|
7
|
+
* so `fetch` really is a polyfill over XMLHttpRequest and hooking XHR alone
|
|
8
|
+
* would cover everything. But **Expo replaces it**: `expo/src/winter/runtime.native.ts`
|
|
9
|
+
* installs `expo/fetch` — a NATIVE fetch over `ExpoFetchModule` — as
|
|
10
|
+
* `globalThis.fetch` unless `EXPO_PUBLIC_USE_RN_FETCH=1`. Those requests never
|
|
11
|
+
* construct an XMLHttpRequest, so an XHR-only override silently does nothing on
|
|
12
|
+
* the majority of real apps.
|
|
13
|
+
*
|
|
14
|
+
* Verified the hard way on Expo SDK 56 / RN 0.85.3: rule matched, engine
|
|
15
|
+
* healthy, interceptor installed, and the request still came back a real 200.
|
|
16
|
+
*
|
|
17
|
+
* So overrides hook BOTH layers. `axios` still needs the XHR path (it uses
|
|
18
|
+
* XMLHttpRequest on every platform), and this covers `fetch` on both flavours.
|
|
19
|
+
*/
|
|
20
|
+
import type { OverrideOutcome } from "./types";
|
|
21
|
+
export declare const sleep: (ms: number) => Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Can we build a `Response` in this runtime?
|
|
24
|
+
*
|
|
25
|
+
* React Native installs the whatwg-fetch `Response` global via `setUpXHR`, and
|
|
26
|
+
* Expo deliberately keeps it (it only swaps `fetch`). Feature-detected anyway:
|
|
27
|
+
* without it, the honest thing is to let the request run for real.
|
|
28
|
+
*/
|
|
29
|
+
export declare function canSynthesizeResponse(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Build the fake `Response` an overridden `fetch` resolves with.
|
|
32
|
+
*
|
|
33
|
+
* Note the status range: whatwg-fetch's `Response` constructor THROWS
|
|
34
|
+
* `RangeError` outside [200, 599], which would crash the caller instead of
|
|
35
|
+
* overriding it. `resolveOverride` clamps before we ever get here.
|
|
36
|
+
*/
|
|
37
|
+
export declare function synthesizeResponse(url: string, outcome: Extract<OverrideOutcome, {
|
|
38
|
+
kind: "respond";
|
|
39
|
+
}>): Response;
|
|
40
|
+
/**
|
|
41
|
+
* The error a failed `fetch` rejects with.
|
|
42
|
+
*
|
|
43
|
+
* These are the exact messages whatwg-fetch produces for a dead connection and
|
|
44
|
+
* a timeout, so app code that string-matches on them (plenty does) behaves the
|
|
45
|
+
* same way it would against a real failure.
|
|
46
|
+
*/
|
|
47
|
+
export declare function synthesizeFetchError(outcome: Extract<OverrideOutcome, {
|
|
48
|
+
kind: "fail";
|
|
49
|
+
}>): Error;
|
|
50
|
+
//# sourceMappingURL=applyToFetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyToFetch.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/applyToFetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAGxB,CAAC;AAExB;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GACrD,QAAQ,CAeV;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,KAAK,CAMP"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perform an override outcome against a React Native XMLHttpRequest.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS POSSIBLE AT ALL: React Native's XMLHttpRequest
|
|
5
|
+
* (`react-native/Libraries/Network/XMLHttpRequest.js`) is pure JavaScript.
|
|
6
|
+
* `readyState`, `status`, `responseHeaders` and `responseURL` are plain
|
|
7
|
+
* writable fields, and `setResponseHeaders()` / `setReadyState()` are real
|
|
8
|
+
* methods — `setReadyState(DONE)` dispatches the correct terminal event off
|
|
9
|
+
* internal flags (`_aborted` → abort, `_hasError` + `_timedOut` → timeout,
|
|
10
|
+
* `_hasError` → error, otherwise load; always loadend). So a response can be
|
|
11
|
+
* synthesized end to end without touching native code.
|
|
12
|
+
*
|
|
13
|
+
* WHY XHR IS THE ONLY PLACE WE HOOK: `react-native/Libraries/Network/fetch.js`
|
|
14
|
+
* is `require('whatwg-fetch')` — RN's `fetch` IS the polyfill over
|
|
15
|
+
* XMLHttpRequest. Overriding here therefore covers `fetch`, `axios` and raw
|
|
16
|
+
* XHR through one code path, and the fake response flows back up through the
|
|
17
|
+
* polyfill so the tool records it without any extra plumbing.
|
|
18
|
+
*
|
|
19
|
+
* Verified field-for-field on React Native 0.81.4 and 0.85.3.
|
|
20
|
+
*
|
|
21
|
+
* Four non-obvious behaviours are handled below; each one is a real bug if you
|
|
22
|
+
* skip it, and each is commented at the line that fixes it.
|
|
23
|
+
*/
|
|
24
|
+
import type { OverrideOutcome } from "./types";
|
|
25
|
+
/**
|
|
26
|
+
* Can this XMLHttpRequest be driven by hand?
|
|
27
|
+
*
|
|
28
|
+
* The whole technique rests on RN internals, so it is feature-detected rather
|
|
29
|
+
* than assumed: on a browser XMLHttpRequest (react-native-web) these methods
|
|
30
|
+
* don't exist and `status` is a read-only getter. There, overrides no-op and
|
|
31
|
+
* the request goes out for real — degraded, but never broken.
|
|
32
|
+
*/
|
|
33
|
+
export declare function canSynthesize(xhr: XMLHttpRequest): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Apply an outcome to a request that has NOT been sent yet.
|
|
36
|
+
*
|
|
37
|
+
* Returns `false` when this environment can't be driven by hand, in which case
|
|
38
|
+
* the caller must send the request normally.
|
|
39
|
+
*
|
|
40
|
+
* @param passThrough Sends the real request. Only used by `kind: "delay"`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function runOverride(xhr: XMLHttpRequest, url: string, outcome: OverrideOutcome, passThrough: () => void): boolean;
|
|
43
|
+
//# sourceMappingURL=applyToXhr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyToXhr.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/applyToXhr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAkC/C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAM1D;AA+ED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,MAAM,IAAI,GACtB,OAAO,CAiET"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The seam between the interceptor and the rule store.
|
|
3
|
+
*
|
|
4
|
+
* It exists to keep the import graph acyclic: `networkListener` needs rules,
|
|
5
|
+
* and the rule store needs the listener (to keep the swizzle installed while a
|
|
6
|
+
* rule is active). Rather than have them import each other, the store REGISTERS
|
|
7
|
+
* itself here and the listener asks here. Both sides import only this leaf.
|
|
8
|
+
*
|
|
9
|
+
* It's also the single place the production gate lives — see `overrideForRequest`.
|
|
10
|
+
*/
|
|
11
|
+
import type { OverrideOutcome, OverrideRule } from "./types";
|
|
12
|
+
export interface OverrideHooks {
|
|
13
|
+
getRules: () => readonly OverrideRule[];
|
|
14
|
+
/** The rule APPLIED to a request. */
|
|
15
|
+
recordHit: (ruleId: string) => void;
|
|
16
|
+
/**
|
|
17
|
+
* The rule MATCHED a request, whether or not it applied.
|
|
18
|
+
*
|
|
19
|
+
* `alternate` needs this: a rule that only counted the requests it overrode
|
|
20
|
+
* would never advance past its off phase, so it would skip forever.
|
|
21
|
+
*/
|
|
22
|
+
recordMatch: (ruleId: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function setOverrideHooks(next: OverrideHooks | null): void;
|
|
25
|
+
/**
|
|
26
|
+
* Diagnostics for the sync adapter's `debugOverrides` action.
|
|
27
|
+
*
|
|
28
|
+
* Reads the engine's own view of the world — crucially `hooks`, which is
|
|
29
|
+
* MODULE state here: if the interceptor and the rule store ever ended up with
|
|
30
|
+
* separate copies of this file, this is the only place that shows it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function inspectEngine(url: string, method: string): {
|
|
33
|
+
hooksInstalled: boolean;
|
|
34
|
+
devFlag: string | boolean;
|
|
35
|
+
ruleCount: number;
|
|
36
|
+
matches: boolean;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Resolve an override for one outgoing request, recording the hit.
|
|
40
|
+
*
|
|
41
|
+
* NEVER ACTIVE IN A PRODUCTION BUILD. A shipped app that synthesizes 500s or
|
|
42
|
+
* silently swallows requests is a catastrophe of a different order than a
|
|
43
|
+
* broken dev tool, so the gate is here — at the single entry point — rather
|
|
44
|
+
* than trusted to every call site.
|
|
45
|
+
*/
|
|
46
|
+
export declare function overrideForRequest(url: string, method: string): OverrideOutcome | null;
|
|
47
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,SAAS,YAAY,EAAE,CAAC;IACxC,qCAAqC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;;;OAKG;IACH,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAEjE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;EAWxD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,IAAI,CAqBxB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glob matching for override rules — a faithful port of Chrome DevTools'.
|
|
3
|
+
*
|
|
4
|
+
* Ported from `NetworkPersistenceManager.ts:1051` + `StringUtilities.ts:9` in
|
|
5
|
+
* the devtools-frontend source. Ported rather than reinvented on purpose: `*`
|
|
6
|
+
* globs are the syntax developers already have in their fingers from Chrome's
|
|
7
|
+
* "Override headers" `applyTo` field, and a pattern that behaves differently
|
|
8
|
+
* here than it does in the browser would be a quiet trap.
|
|
9
|
+
*/
|
|
10
|
+
import type { OverrideRule } from "./types";
|
|
11
|
+
/**
|
|
12
|
+
* Escape a glob into regex source: neutralize regex metacharacters, then
|
|
13
|
+
* promote `*` to `.*`.
|
|
14
|
+
*
|
|
15
|
+
* `split`/`join` rather than `replaceAll` — same result, no reliance on how
|
|
16
|
+
* complete a given Hermes build's ES2021 surface is.
|
|
17
|
+
*/
|
|
18
|
+
export declare function escapeRegex(pattern: string): string;
|
|
19
|
+
export declare function compilePattern(pattern: string): RegExp;
|
|
20
|
+
/** Does this rule apply to this request? Ignores `enabled` — callers check it. */
|
|
21
|
+
export declare function ruleMatches(rule: OverrideRule, url: string, method: string): boolean;
|
|
22
|
+
//# sourceMappingURL=matchRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchRule.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/matchRule.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAU5C;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUnD;AAWD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CACzB,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAWT"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The override rule list — persisted, and the source of truth for the engine.
|
|
3
|
+
*
|
|
4
|
+
* Shape and persistence follow `networkSavedStore` / `ignoredPatternsStore`:
|
|
5
|
+
* lazy hydrate on first use, a `dirty` flag so a slow read can't clobber a
|
|
6
|
+
* mutation the user just made, and commit = set + emit + persist.
|
|
7
|
+
*
|
|
8
|
+
* Two things here are specific to overrides and worth reading:
|
|
9
|
+
*
|
|
10
|
+
* - `getRules()` is on the HOT PATH. It is called inside the app's own
|
|
11
|
+
* `XMLHttpRequest.send()`, for every request, so it does no work: the master
|
|
12
|
+
* switch collapses to returning a frozen empty array.
|
|
13
|
+
*
|
|
14
|
+
* - `syncKeepAlive()` keeps the interceptor installed while any rule is
|
|
15
|
+
* active. Without it a rule would stop firing the moment the Network tool
|
|
16
|
+
* closed, because the swizzle is reference-counted off capture subscribers.
|
|
17
|
+
*/
|
|
18
|
+
import { type OverrideRule } from "./types";
|
|
19
|
+
export interface OverrideRulesState {
|
|
20
|
+
/** Master switch. Off disables every rule without losing any of them. */
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
rules: OverrideRule[];
|
|
23
|
+
/**
|
|
24
|
+
* Set when the launch-safety guard turned overrides off by itself.
|
|
25
|
+
*
|
|
26
|
+
* Cleared the moment the developer turns them back on or touches a rule. The
|
|
27
|
+
* UI uses it to explain the state rather than leave it looking like a bug.
|
|
28
|
+
*/
|
|
29
|
+
autoPaused: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A rule as authored. `id`/`createdAt` and the runtime counters (`hits`,
|
|
33
|
+
* `seen`) are the store's business, never the caller's.
|
|
34
|
+
*/
|
|
35
|
+
export type OverrideRuleDraft = Omit<OverrideRule, "id" | "hits" | "seen" | "createdAt">;
|
|
36
|
+
/**
|
|
37
|
+
* Handlers the desktop dashboard installs to forward mutations to the device.
|
|
38
|
+
*
|
|
39
|
+
* Rules only DO anything on the device — a rule is applied inside the app's own
|
|
40
|
+
* `fetch`/`XMLHttpRequest`, which the dashboard doesn't have. So in remote mode
|
|
41
|
+
* this store becomes a MIRROR: it renders the device's rules and forwards every
|
|
42
|
+
* edit, writing nothing to this machine's storage. Same seam
|
|
43
|
+
* `networkSavedStore` uses for pins.
|
|
44
|
+
*/
|
|
45
|
+
export interface OverrideRulesRemote {
|
|
46
|
+
setEnabled: (enabled: boolean) => void;
|
|
47
|
+
upsertRule: (draft: OverrideRuleDraft & {
|
|
48
|
+
id?: string;
|
|
49
|
+
}) => void;
|
|
50
|
+
setRuleEnabled: (id: string, enabled: boolean) => void;
|
|
51
|
+
removeRule: (id: string) => void;
|
|
52
|
+
clearRules: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the body the snapshot withheld (see `OverrideRule.bodyOmitted`).
|
|
55
|
+
* Optional so an older dashboard still mirrors rules — it just shows an empty
|
|
56
|
+
* body for the large ones.
|
|
57
|
+
*/
|
|
58
|
+
getRuleBody?: (id: string) => Promise<string | null>;
|
|
59
|
+
}
|
|
60
|
+
type Listener = () => void;
|
|
61
|
+
declare class OverrideRulesStore {
|
|
62
|
+
private rules;
|
|
63
|
+
private enabled;
|
|
64
|
+
private readonly listeners;
|
|
65
|
+
private loaded;
|
|
66
|
+
private loadPromise;
|
|
67
|
+
/** Set once a mutation happens so a slow initial load can't clobber it. */
|
|
68
|
+
private dirty;
|
|
69
|
+
private idCounter;
|
|
70
|
+
private state;
|
|
71
|
+
/** Consecutive launches that began with rules armed and nobody touching them. */
|
|
72
|
+
private launchStreak;
|
|
73
|
+
private autoPaused;
|
|
74
|
+
/** Held while any rule is active — see `syncKeepAlive`. */
|
|
75
|
+
private keepAlive;
|
|
76
|
+
private hitEmitTimer;
|
|
77
|
+
/** Set on the desktop dashboard — see `disableEngine`. */
|
|
78
|
+
private engineDisabled;
|
|
79
|
+
/** Set on the desktop dashboard — see `OverrideRulesRemote`. */
|
|
80
|
+
private remote;
|
|
81
|
+
private remoteEchoUntil;
|
|
82
|
+
/**
|
|
83
|
+
* Turn this store into a mirror of a connected device's rules. Edits are
|
|
84
|
+
* applied locally for immediate feedback AND forwarded to the device, which
|
|
85
|
+
* is the source of truth; nothing is persisted to this machine.
|
|
86
|
+
*/
|
|
87
|
+
enableRemoteMode(remote: OverrideRulesRemote): void;
|
|
88
|
+
disableRemoteMode(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Feed the device's rules in (mirror mode only). `force` bypasses the echo
|
|
91
|
+
* guard — used when tearing the mirror down, where there is no later snapshot
|
|
92
|
+
* to converge on.
|
|
93
|
+
*/
|
|
94
|
+
replaceRules(state: OverrideRulesState, force?: boolean): void;
|
|
95
|
+
/** Mark a local optimistic write so the next in-flight mirror is ignored. */
|
|
96
|
+
private markLocalEdit;
|
|
97
|
+
/**
|
|
98
|
+
* Never intercept traffic in this runtime.
|
|
99
|
+
*
|
|
100
|
+
* The desktop dashboard renders the real tool (`NetworkToolView`), so this
|
|
101
|
+
* module is imported there too — but the dashboard is a VIEWER. Its job is to
|
|
102
|
+
* drive rules on the connected device, never to swizzle its own `fetch` and
|
|
103
|
+
* override its own requests. The same seam `networkEventStore.disableCapture()`
|
|
104
|
+
* uses, for the same reason.
|
|
105
|
+
*/
|
|
106
|
+
disableEngine(): void;
|
|
107
|
+
getState(): OverrideRulesState;
|
|
108
|
+
/**
|
|
109
|
+
* The hot path — called inside `send()` for every request the app makes.
|
|
110
|
+
* Returns a frozen empty array when the master switch is off so the caller
|
|
111
|
+
* needs no second check.
|
|
112
|
+
*/
|
|
113
|
+
getRules(): readonly OverrideRule[];
|
|
114
|
+
/**
|
|
115
|
+
* The rule's real body, fetching it from the device when this surface only
|
|
116
|
+
* has the stripped copy (see `OverrideRule.bodyOmitted`).
|
|
117
|
+
*
|
|
118
|
+
* On the device itself every body is already here, so this resolves
|
|
119
|
+
* immediately and the editor never notices the difference.
|
|
120
|
+
*/
|
|
121
|
+
fetchRuleBody(id: string): Promise<string | null>;
|
|
122
|
+
/** Rules that would actually fire — drives the "overrides active" banner. */
|
|
123
|
+
activeCount(): number;
|
|
124
|
+
subscribe(listener: Listener): () => void;
|
|
125
|
+
setEnabled(enabled: boolean): void;
|
|
126
|
+
addRule(draft: OverrideRuleDraft): OverrideRule | null;
|
|
127
|
+
/**
|
|
128
|
+
* Create or replace a rule in one call.
|
|
129
|
+
*
|
|
130
|
+
* THE ONLY WRITE PATH THE UI SHOULD USE. `addRule`/`updateRule` are the
|
|
131
|
+
* primitives underneath and deliberately do NOT forward to the device — if
|
|
132
|
+
* the UI called them directly, an edit made on the dashboard would apply to
|
|
133
|
+
* the mirror and never reach the phone, which looks exactly like it worked.
|
|
134
|
+
*
|
|
135
|
+
* Returns the rule, or null when the list is full.
|
|
136
|
+
*/
|
|
137
|
+
upsertRule(draft: OverrideRuleDraft & {
|
|
138
|
+
id?: string;
|
|
139
|
+
}): OverrideRule | null;
|
|
140
|
+
updateRule(id: string, patch: Partial<OverrideRuleDraft>): void;
|
|
141
|
+
setRuleEnabled(id: string, enabled: boolean): void;
|
|
142
|
+
removeRule(id: string): void;
|
|
143
|
+
clearRules(): void;
|
|
144
|
+
/**
|
|
145
|
+
* One rule matched one request.
|
|
146
|
+
*
|
|
147
|
+
* Replaces the rule object rather than mutating it so memoized rows actually
|
|
148
|
+
* re-render, and coalesces the notification — this runs at request rate.
|
|
149
|
+
*/
|
|
150
|
+
/**
|
|
151
|
+
* One rule matched one request, applied or not.
|
|
152
|
+
*
|
|
153
|
+
* Deliberately silent — this fires on requests an alternating rule lets
|
|
154
|
+
* through, where nothing visible changed. `recordHit` owns the notification.
|
|
155
|
+
*/
|
|
156
|
+
recordMatch(ruleId: string): void;
|
|
157
|
+
recordHit(ruleId: string): void;
|
|
158
|
+
/**
|
|
159
|
+
* Hydrate from storage. Safe to call repeatedly; only the first call reads.
|
|
160
|
+
*
|
|
161
|
+
* Called at package import (see `preset.tsx`) rather than on first subscribe,
|
|
162
|
+
* because a rule has to fire from app boot — with the Network tool closed and
|
|
163
|
+
* nothing capturing.
|
|
164
|
+
*/
|
|
165
|
+
ensureLoaded(): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* Count this launch, and pause overrides if they've been armed and untouched
|
|
168
|
+
* for too many in a row. See MAX_UNTOUCHED_LAUNCHES for why.
|
|
169
|
+
*/
|
|
170
|
+
private applyLaunchGuard;
|
|
171
|
+
/**
|
|
172
|
+
* Keep the interceptor installed for as long as a rule could fire.
|
|
173
|
+
*
|
|
174
|
+
* The swizzle is reference-counted off `networkListener`'s listener count
|
|
175
|
+
* (the event store adds one while capturing). Holding a no-op listener reuses
|
|
176
|
+
* that existing lifecycle instead of inventing a second one.
|
|
177
|
+
*/
|
|
178
|
+
private syncKeepAlive;
|
|
179
|
+
private scheduleHitEmit;
|
|
180
|
+
private commit;
|
|
181
|
+
/** Rebuild the derived view once per mutation so renders get stable refs. */
|
|
182
|
+
private rebuild;
|
|
183
|
+
/**
|
|
184
|
+
* The developer is actively working with the rules, so the launch guard has
|
|
185
|
+
* nothing to protect them from — reset it and clear any auto-pause notice.
|
|
186
|
+
*/
|
|
187
|
+
private markTouched;
|
|
188
|
+
/**
|
|
189
|
+
* The developer reached the override UI, which is proof the app still runs.
|
|
190
|
+
*
|
|
191
|
+
* The launch guard exists to escape a WEDGE — a body the app can't render,
|
|
192
|
+
* where the controls are unreachable because nothing draws. If this call
|
|
193
|
+
* happens, that isn't the situation, so the streak has nothing to protect
|
|
194
|
+
* against. Without it the guard nags anyone who legitimately keeps a rule
|
|
195
|
+
* armed for days, which is a real workflow ("force /checkout to 500 every
|
|
196
|
+
* morning") and not the failure mode it was built for.
|
|
197
|
+
*/
|
|
198
|
+
noteHealthyLaunch(): void;
|
|
199
|
+
private persist;
|
|
200
|
+
private emit;
|
|
201
|
+
}
|
|
202
|
+
/** Singleton — one rule list per JS runtime. */
|
|
203
|
+
export declare const overrideRulesStore: OverrideRulesStore;
|
|
204
|
+
export {};
|
|
205
|
+
//# sourceMappingURL=overrideRulesStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overrideRulesStore.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/overrideRulesStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a captured request into a rule draft.
|
|
3
|
+
*
|
|
4
|
+
* Chrome's flow assumes a keyboard, a file tree and a second monitor. On a
|
|
5
|
+
* phone the equivalent has to start from the request you're already looking at,
|
|
6
|
+
* which is what this file is for — the editor never opens on a blank field.
|
|
7
|
+
*
|
|
8
|
+
* There used to be a list of one-tap presets here (Force 500, Empty list,
|
|
9
|
+
* Offline…) rendered as chips. They're gone: the editor's outcome grid says the
|
|
10
|
+
* same things in the same words, so keeping both meant two lists to maintain
|
|
11
|
+
* and two places to look for the same choice.
|
|
12
|
+
*/
|
|
13
|
+
import type { NetworkEvent } from "../types";
|
|
14
|
+
import type { OverrideRuleDraft } from "./overrideRulesStore";
|
|
15
|
+
/**
|
|
16
|
+
* Turn a captured URL into a pattern that will match the request AGAIN.
|
|
17
|
+
*
|
|
18
|
+
* The query string is dropped and replaced with `*`, which is not a
|
|
19
|
+
* simplification — it's the difference between a rule that works and one that
|
|
20
|
+
* silently never fires. Plenty of clients cache-bust
|
|
21
|
+
* (`?timestamp=1785783081234`), carry a request id, or page; pinning the exact
|
|
22
|
+
* URL means the next call to the same endpoint doesn't match. Found exactly
|
|
23
|
+
* that way: an "Offline" preset on a Pokémon request sat at 0 hits because the
|
|
24
|
+
* app appends a timestamp to every call.
|
|
25
|
+
*
|
|
26
|
+
* The path stays exact, so this still means "this endpoint" and not "this
|
|
27
|
+
* host" — and the editor shows the pattern, so narrowing it back down is one
|
|
28
|
+
* edit away.
|
|
29
|
+
*/
|
|
30
|
+
export declare function patternForUrl(url: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Prefill the rule editor from a captured request.
|
|
33
|
+
*
|
|
34
|
+
* Seeds the REAL response as the body so the common edit — change two fields of
|
|
35
|
+
* a payload you just saw — starts from something true rather than from nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function draftFromEvent(event: NetworkEvent): OverrideRuleDraft;
|
|
38
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGjD;AAaD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,CAYrE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decide whether a request is overridden — the whole decision, in one pure
|
|
3
|
+
* function.
|
|
4
|
+
*
|
|
5
|
+
* Pure on purpose: this is the piece worth unit-testing, and it runs inside the
|
|
6
|
+
* app's own `XMLHttpRequest.send()`, so it must be cheap, total, and incapable
|
|
7
|
+
* of throwing. Everything that could surprise (defaults, clamping, content-type
|
|
8
|
+
* inference) is resolved HERE, so `applyToXhr` never makes a decision — it just
|
|
9
|
+
* performs the outcome.
|
|
10
|
+
*/
|
|
11
|
+
import { type OverrideOutcome, type OverrideRule } from "./types";
|
|
12
|
+
/** Normalize a matched rule into the exact instructions the interceptor needs. */
|
|
13
|
+
declare function toOutcome(rule: OverrideRule): OverrideOutcome;
|
|
14
|
+
/** A rule that has burned through its `times` budget no longer applies. */
|
|
15
|
+
export declare function isSpent(rule: OverrideRule): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Is this rule in a phase where it should actually fire?
|
|
18
|
+
*
|
|
19
|
+
* Only `alternate` can answer no. It reads the CURRENT `seen` count, before
|
|
20
|
+
* this match is recorded, so an untouched rule (`seen === 0`) lets the first
|
|
21
|
+
* request through and overrides the second.
|
|
22
|
+
*/
|
|
23
|
+
export declare function shouldApply(rule: OverrideRule): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The first enabled rule whose pattern covers this request, phase ignored.
|
|
26
|
+
*
|
|
27
|
+
* Separate from `resolveOverride` because an alternating rule has to advance
|
|
28
|
+
* its phase on the requests it deliberately skips — the caller needs the rule
|
|
29
|
+
* back even when the answer is "not this time".
|
|
30
|
+
*/
|
|
31
|
+
export declare function findMatchingRule(url: string, method: string, rules: readonly OverrideRule[]): OverrideRule | null;
|
|
32
|
+
/**
|
|
33
|
+
* First ENABLED matching rule wins outright — no merging across rules.
|
|
34
|
+
*
|
|
35
|
+
* Chrome cascades header overrides from the most general path segment to the
|
|
36
|
+
* most specific, but that only exists because its rules are directory-nested
|
|
37
|
+
* files. A flat list with a cascade would be a rule whose effect you cannot see
|
|
38
|
+
* by reading it, which is exactly the wrong trade on a phone screen.
|
|
39
|
+
*
|
|
40
|
+
* @param url Full request URL, query string included.
|
|
41
|
+
* @param method HTTP method as the caller sent it (case-insensitive).
|
|
42
|
+
* @param rules Ordered rule list; earlier entries win.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveOverride(url: string, method: string, rules: readonly OverrideRule[]): OverrideOutcome | null;
|
|
45
|
+
export { toOutcome };
|
|
46
|
+
//# sourceMappingURL=resolveOverride.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveOverride.d.ts","sourceRoot":"","sources":["../../../../src/network/overrides/resolveOverride.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,SAAS,CAAC;AA4CjB,kFAAkF;AAClF,iBAAS,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,CA6BtD;AAED,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAGvD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,YAAY,GAAG,IAAI,CAcrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,eAAe,GAAG,IAAI,CAIxB;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|