@buoy-gg/network 7.0.40 → 7.0.42
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 +11 -79
- package/lib/commonjs/index.js +1 -325
- package/lib/commonjs/index.web.js +1 -420
- package/lib/commonjs/network/components/DataViewer.web.js +1 -879
- package/lib/commonjs/network/components/NetworkCopyScreen.web.js +1 -48
- package/lib/commonjs/network/components/NetworkCopySettingsView.js +27 -755
- package/lib/commonjs/network/components/NetworkCopySettingsView.web.js +14 -1242
- package/lib/commonjs/network/components/NetworkDetailScreen.web.js +1 -101
- package/lib/commonjs/network/components/NetworkDetailStepper.js +1 -108
- package/lib/commonjs/network/components/NetworkDetailStepper.web.js +1 -298
- package/lib/commonjs/network/components/NetworkEventDetailView.js +15 -1130
- package/lib/commonjs/network/components/NetworkEventDetailView.web.js +15 -1484
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +2 -401
- package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +2 -820
- package/lib/commonjs/network/components/NetworkFilterScreen.web.js +1 -55
- package/lib/commonjs/network/components/NetworkFilterViewV3.js +1 -442
- package/lib/commonjs/network/components/NetworkFilterViewV3.web.js +1 -1310
- package/lib/commonjs/network/components/NetworkHeaderLive.js +1 -375
- package/lib/commonjs/network/components/NetworkHeaderLive.web.js +1 -623
- package/lib/commonjs/network/components/NetworkHeaderMenu.js +1 -190
- package/lib/commonjs/network/components/NetworkListScreen.js +1 -404
- package/lib/commonjs/network/components/NetworkListScreen.web.js +1 -625
- package/lib/commonjs/network/components/NetworkModal.js +1 -786
- package/lib/commonjs/network/components/NetworkNumberPrompt.js +1 -178
- package/lib/commonjs/network/components/NetworkNumberPrompt.web.js +1 -232
- package/lib/commonjs/network/components/NetworkOverrideEditor.js +1 -814
- package/lib/commonjs/network/components/NetworkOverrideEditor.web.js +1 -942
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +1 -107
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.web.js +1 -133
- package/lib/commonjs/network/components/NetworkOverridesButton.js +1 -90
- package/lib/commonjs/network/components/NetworkOverridesButton.web.js +1 -143
- package/lib/commonjs/network/components/NetworkOverridesScreen.js +1 -543
- package/lib/commonjs/network/components/NetworkOverridesScreen.web.js +1 -830
- package/lib/commonjs/network/components/NetworkSavedScreen.js +1 -226
- package/lib/commonjs/network/components/NetworkSavedScreen.web.js +1 -463
- package/lib/commonjs/network/components/NetworkUpgradeBanner.js +1 -76
- package/lib/commonjs/network/components/response-editor/Explorer.js +1 -973
- package/lib/commonjs/network/components/response-editor/Explorer.web.js +1 -1136
- package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +1 -56
- package/lib/commonjs/network/components/response-editor/editorContext.js +1 -33
- package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +1 -61
- package/lib/commonjs/network/conditions/NetworkConditionsControl.js +1 -235
- package/lib/commonjs/network/conditions/NetworkConditionsControl.test.js +1 -136
- package/lib/commonjs/network/conditions/NetworkConditionsIcon.js +1 -33
- package/lib/commonjs/network/conditions/NetworkFloatingTool.js +1 -310
- package/lib/commonjs/network/conditions/NetworkFloatingTool.test.js +1 -219
- package/lib/commonjs/network/conditions/store.js +1 -75
- package/lib/commonjs/network/conditions/wait.js +1 -43
- package/lib/commonjs/network/conditions/xhr.js +1 -110
- package/lib/commonjs/network/hooks/useLiveNetworkEvent.js +1 -62
- package/lib/commonjs/network/hooks/useNetworkBadgeCounts.js +1 -83
- package/lib/commonjs/network/hooks/useNetworkEventList.js +1 -108
- package/lib/commonjs/network/hooks/useNetworkEvents.js +1 -318
- package/lib/commonjs/network/hooks/useNetworkHasMatches.js +1 -56
- package/lib/commonjs/network/hooks/useNetworkSaved.js +1 -38
- package/lib/commonjs/network/hooks/useNetworkSelection.js +1 -53
- package/lib/commonjs/network/hooks/useOverrideRules.js +1 -36
- package/lib/commonjs/network/hooks/useTickEveryMinute.js +1 -21
- package/lib/commonjs/network/overrides/applyToFetch.js +1 -80
- package/lib/commonjs/network/overrides/applyToXhr.js +2 -453
- package/lib/commonjs/network/overrides/engine.js +1 -93
- package/lib/commonjs/network/overrides/matchRule.js +1 -81
- package/lib/commonjs/network/overrides/overriddenRows.js +1 -0
- package/lib/commonjs/network/overrides/overrideRulesStore.js +1 -550
- package/lib/commonjs/network/overrides/presets.js +1 -70
- package/lib/commonjs/network/overrides/resolveOverride.js +1 -158
- package/lib/commonjs/network/overrides/types.js +1 -90
- package/lib/commonjs/network/sync/networkBodyResolver.js +1 -39
- package/lib/commonjs/network/sync/networkSyncAdapter.js +1 -882
- package/lib/commonjs/network/sync/overrideHonesty.release.test.js +1 -36
- package/lib/commonjs/network/types/index.js +1 -5
- package/lib/commonjs/network/utils/extractOperationName.js +1 -80
- package/lib/commonjs/network/utils/filterNetworkEvents.js +1 -96
- package/lib/commonjs/network/utils/formatGraphQLVariables.js +1 -219
- package/lib/commonjs/network/utils/formatting.js +1 -30
- package/lib/commonjs/network/utils/generateCurl.js +2 -71
- package/lib/commonjs/network/utils/generateNetworkCopyText.js +37 -166
- package/lib/commonjs/network/utils/httpCompletion.js +1 -37
- package/lib/commonjs/network/utils/networkEventStore.js +1 -393
- package/lib/commonjs/network/utils/networkListener.js +4 -1259
- package/lib/commonjs/network/utils/networkSavedStore.js +3 -577
- package/lib/commonjs/network/utils/networkSelectionStore.js +1 -193
- package/lib/commonjs/network/utils/realNow.js +1 -0
- package/lib/commonjs/network/utils/requestId.js +1 -0
- package/lib/commonjs/network/utils/resolveRequestUrl.js +1 -0
- package/lib/commonjs/network/utils/selectSavedEvents.js +1 -39
- package/lib/commonjs/network/utils/startNetworkCapture.js +1 -0
- package/lib/commonjs/network/utils/withPinnedFirst.js +1 -32
- package/lib/commonjs/preset.js +1 -102
- package/lib/module/index.js +1 -103
- package/lib/module/index.web.js +1 -82
- package/lib/module/network/components/DataViewer.web.js +1 -875
- package/lib/module/network/components/NetworkCopyScreen.web.js +1 -44
- package/lib/module/network/components/NetworkCopySettingsView.js +27 -750
- package/lib/module/network/components/NetworkCopySettingsView.web.js +14 -1237
- package/lib/module/network/components/NetworkDetailScreen.web.js +1 -97
- package/lib/module/network/components/NetworkDetailStepper.js +1 -104
- package/lib/module/network/components/NetworkDetailStepper.web.js +1 -296
- package/lib/module/network/components/NetworkEventDetailView.js +15 -1129
- package/lib/module/network/components/NetworkEventDetailView.web.js +15 -1482
- package/lib/module/network/components/NetworkEventItemCompact.js +2 -398
- package/lib/module/network/components/NetworkEventItemCompact.web.js +2 -818
- package/lib/module/network/components/NetworkFilterScreen.web.js +1 -51
- package/lib/module/network/components/NetworkFilterViewV3.js +1 -438
- package/lib/module/network/components/NetworkFilterViewV3.web.js +1 -1306
- package/lib/module/network/components/NetworkHeaderLive.js +1 -366
- package/lib/module/network/components/NetworkHeaderLive.web.js +1 -617
- package/lib/module/network/components/NetworkHeaderMenu.js +1 -184
- package/lib/module/network/components/NetworkListScreen.js +1 -400
- package/lib/module/network/components/NetworkListScreen.web.js +1 -623
- package/lib/module/network/components/NetworkModal.js +1 -781
- package/lib/module/network/components/NetworkNumberPrompt.js +1 -174
- package/lib/module/network/components/NetworkNumberPrompt.web.js +1 -230
- package/lib/module/network/components/NetworkOverrideEditor.js +1 -811
- package/lib/module/network/components/NetworkOverrideEditor.web.js +1 -939
- package/lib/module/network/components/NetworkOverrideHeaderButton.js +1 -104
- package/lib/module/network/components/NetworkOverrideHeaderButton.web.js +1 -131
- package/lib/module/network/components/NetworkOverridesButton.js +1 -87
- package/lib/module/network/components/NetworkOverridesButton.web.js +1 -141
- package/lib/module/network/components/NetworkOverridesScreen.js +1 -539
- package/lib/module/network/components/NetworkOverridesScreen.web.js +1 -826
- package/lib/module/network/components/NetworkSavedScreen.js +1 -222
- package/lib/module/network/components/NetworkSavedScreen.web.js +1 -461
- package/lib/module/network/components/NetworkUpgradeBanner.js +1 -72
- package/lib/module/network/components/response-editor/Explorer.js +1 -972
- package/lib/module/network/components/response-editor/Explorer.web.js +1 -1133
- package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +1 -51
- package/lib/module/network/components/response-editor/editorContext.js +1 -29
- package/lib/module/network/components/response-editor/updateNestedDataByPath.js +1 -56
- package/lib/module/network/conditions/NetworkConditionsControl.js +1 -231
- package/lib/module/network/conditions/NetworkConditionsControl.test.js +1 -135
- package/lib/module/network/conditions/NetworkConditionsIcon.js +1 -29
- package/lib/module/network/conditions/NetworkFloatingTool.js +1 -304
- package/lib/module/network/conditions/NetworkFloatingTool.test.js +1 -218
- package/lib/module/network/conditions/store.js +1 -65
- package/lib/module/network/conditions/wait.js +1 -38
- package/lib/module/network/conditions/xhr.js +1 -106
- package/lib/module/network/hooks/useLiveNetworkEvent.js +1 -58
- package/lib/module/network/hooks/useNetworkBadgeCounts.js +1 -79
- package/lib/module/network/hooks/useNetworkEventList.js +1 -104
- package/lib/module/network/hooks/useNetworkEvents.js +1 -314
- package/lib/module/network/hooks/useNetworkHasMatches.js +1 -52
- package/lib/module/network/hooks/useNetworkSaved.js +1 -34
- package/lib/module/network/hooks/useNetworkSelection.js +1 -46
- package/lib/module/network/hooks/useOverrideRules.js +1 -32
- package/lib/module/network/hooks/useTickEveryMinute.js +1 -11
- package/lib/module/network/overrides/applyToFetch.js +1 -72
- package/lib/module/network/overrides/applyToXhr.js +2 -446
- package/lib/module/network/overrides/engine.js +1 -85
- package/lib/module/network/overrides/matchRule.js +1 -75
- package/lib/module/network/overrides/overriddenRows.js +1 -0
- package/lib/module/network/overrides/overrideRulesStore.js +1 -547
- package/lib/module/network/overrides/presets.js +1 -65
- package/lib/module/network/overrides/resolveOverride.js +1 -152
- package/lib/module/network/overrides/types.js +1 -86
- package/lib/module/network/sync/networkBodyResolver.js +1 -34
- package/lib/module/network/sync/networkSyncAdapter.js +1 -880
- package/lib/module/network/sync/overrideHonesty.release.test.js +1 -35
- package/lib/module/network/types/index.js +1 -3
- package/lib/module/network/utils/extractOperationName.js +1 -76
- package/lib/module/network/utils/filterNetworkEvents.js +1 -92
- package/lib/module/network/utils/formatGraphQLVariables.js +1 -213
- package/lib/module/network/utils/formatting.js +1 -9
- package/lib/module/network/utils/generateCurl.js +2 -67
- package/lib/module/network/utils/generateNetworkCopyText.js +37 -162
- package/lib/module/network/utils/httpCompletion.js +1 -32
- package/lib/module/network/utils/networkEventStore.js +1 -391
- package/lib/module/network/utils/networkListener.js +4 -1249
- package/lib/module/network/utils/networkSavedStore.js +3 -572
- package/lib/module/network/utils/networkSelectionStore.js +1 -188
- package/lib/module/network/utils/realNow.js +1 -0
- package/lib/module/network/utils/requestId.js +1 -0
- package/lib/module/network/utils/resolveRequestUrl.js +1 -0
- package/lib/module/network/utils/selectSavedEvents.js +1 -35
- package/lib/module/network/utils/startNetworkCapture.js +1 -0
- package/lib/module/network/utils/withPinnedFirst.js +1 -28
- package/lib/module/preset.js +1 -100
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts +1 -0
- package/lib/typescript/network/overrides/engine.d.ts +1 -1
- package/lib/typescript/network/overrides/matchRule.d.ts +1 -1
- package/lib/typescript/network/overrides/overriddenRows.d.ts +16 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts +2 -2
- package/lib/typescript/network/overrides/types.d.ts +9 -0
- package/lib/typescript/network/utils/networkListener.d.ts +14 -4
- package/lib/typescript/network/utils/networkSavedStore.d.ts +4 -4
- package/lib/typescript/network/utils/realNow.d.ts +18 -0
- package/lib/typescript/network/utils/requestId.d.ts +2 -0
- package/lib/typescript/network/utils/resolveRequestUrl.d.ts +3 -0
- package/lib/typescript/network/utils/startNetworkCapture.d.ts +6 -0
- package/lib/web/index.mjs +145 -0
- package/package.json +32 -10
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/index.web.d.ts.map +0 -1
- package/lib/typescript/network/components/DataViewer.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkCopySettingsView.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkDetailStepper.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkFilterViewV3.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkListScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkModal.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkSavedScreen.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts.map +0 -1
- package/lib/typescript/network/components/NetworkUpgradeBanner.d.ts.map +0 -1
- package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +0 -1
- package/lib/typescript/network/components/response-editor/Explorer.web.d.ts.map +0 -1
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +0 -1
- package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +0 -1
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +0 -1
- package/lib/typescript/network/conditions/NetworkConditionsControl.d.ts.map +0 -1
- package/lib/typescript/network/conditions/NetworkConditionsControl.test.d.ts.map +0 -1
- package/lib/typescript/network/conditions/NetworkConditionsIcon.d.ts.map +0 -1
- package/lib/typescript/network/conditions/NetworkFloatingTool.d.ts.map +0 -1
- package/lib/typescript/network/conditions/NetworkFloatingTool.test.d.ts.map +0 -1
- package/lib/typescript/network/conditions/store.d.ts.map +0 -1
- package/lib/typescript/network/conditions/wait.d.ts.map +0 -1
- package/lib/typescript/network/conditions/xhr.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useLiveNetworkEvent.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkBadgeCounts.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkEvents.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkHasMatches.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkSaved.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useNetworkSelection.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +0 -1
- package/lib/typescript/network/hooks/useTickEveryMinute.d.ts.map +0 -1
- package/lib/typescript/network/overrides/applyToFetch.d.ts.map +0 -1
- package/lib/typescript/network/overrides/applyToXhr.d.ts.map +0 -1
- package/lib/typescript/network/overrides/engine.d.ts.map +0 -1
- package/lib/typescript/network/overrides/matchRule.d.ts.map +0 -1
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +0 -1
- package/lib/typescript/network/overrides/presets.d.ts.map +0 -1
- package/lib/typescript/network/overrides/resolveOverride.d.ts.map +0 -1
- package/lib/typescript/network/overrides/types.d.ts.map +0 -1
- package/lib/typescript/network/sync/networkBodyResolver.d.ts.map +0 -1
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/network/sync/overrideHonesty.release.test.d.ts.map +0 -1
- package/lib/typescript/network/types/index.d.ts.map +0 -1
- package/lib/typescript/network/utils/extractOperationName.d.ts.map +0 -1
- package/lib/typescript/network/utils/filterNetworkEvents.d.ts.map +0 -1
- package/lib/typescript/network/utils/formatGraphQLVariables.d.ts.map +0 -1
- package/lib/typescript/network/utils/formatting.d.ts.map +0 -1
- package/lib/typescript/network/utils/generateCurl.d.ts.map +0 -1
- package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +0 -1
- package/lib/typescript/network/utils/httpCompletion.d.ts.map +0 -1
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +0 -1
- package/lib/typescript/network/utils/networkListener.d.ts.map +0 -1
- package/lib/typescript/network/utils/networkSavedStore.d.ts.map +0 -1
- package/lib/typescript/network/utils/networkSelectionStore.d.ts.map +0 -1
- package/lib/typescript/network/utils/selectSavedEvents.d.ts.map +0 -1
- package/lib/typescript/network/utils/withPinnedFirst.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
|
@@ -1,446 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Perform an override outcome against an XMLHttpRequest — React Native's OR a
|
|
5
|
-
* standards (browser/webview) one.
|
|
6
|
-
*
|
|
7
|
-
* WHY THIS IS POSSIBLE ON RN: React Native's XMLHttpRequest
|
|
8
|
-
* (`react-native/Libraries/Network/XMLHttpRequest.js`) is pure JavaScript.
|
|
9
|
-
* `readyState`, `status`, `responseHeaders` and `responseURL` are plain
|
|
10
|
-
* writable fields, and `setResponseHeaders()` / `setReadyState()` are real
|
|
11
|
-
* methods — `setReadyState(DONE)` dispatches the correct terminal event off
|
|
12
|
-
* internal flags (`_aborted` → abort, `_hasError` + `_timedOut` → timeout,
|
|
13
|
-
* `_hasError` → error, otherwise load; always loadend). So a response can be
|
|
14
|
-
* synthesized end to end without touching native code.
|
|
15
|
-
*
|
|
16
|
-
* WHY XHR IS THE ONLY PLACE WE HOOK ON RN:
|
|
17
|
-
* `react-native/Libraries/Network/fetch.js` is `require('whatwg-fetch')` —
|
|
18
|
-
* RN's `fetch` IS the polyfill over XMLHttpRequest. Overriding here therefore
|
|
19
|
-
* covers `fetch`, `axios` and raw XHR through one code path, and the fake
|
|
20
|
-
* response flows back up through the polyfill so the tool records it without
|
|
21
|
-
* any extra plumbing.
|
|
22
|
-
*
|
|
23
|
-
* Verified field-for-field on React Native 0.81.4 and 0.85.3.
|
|
24
|
-
*
|
|
25
|
-
* WHY THERE IS A SECOND PATH: on a STANDARDS XMLHttpRequest (a webview port —
|
|
26
|
-
* Tauri/Capacitor — or react-native-web) none of the RN internals exist, and
|
|
27
|
-
* `status` / `readyState` / `response` are readonly ACCESSORS on
|
|
28
|
-
* `XMLHttpRequest.prototype`, so plain assignment silently no-ops (or throws
|
|
29
|
-
* in strict mode). This file used to feature-detect that and give up —
|
|
30
|
-
* "degraded, but never broken" — which was right for react-native-web as a
|
|
31
|
-
* by-product of an RN app, and wrong the moment the web ports made the
|
|
32
|
-
* browser XHR a first-class target: the row got FLAGGED as overridden (the
|
|
33
|
-
* rule matched) while the real request went out. The fix is
|
|
34
|
-
* `runStandardOverride` below: `Object.defineProperty` INSTANCE own-properties
|
|
35
|
-
* shadow the prototype accessors (legal on any object), and the lifecycle
|
|
36
|
-
* events are dispatched by hand through the XHR's own EventTarget — which
|
|
37
|
-
* fires `addEventListener` listeners AND the `onload`/`onloadend`/
|
|
38
|
-
* `onreadystatechange` handler attributes, exactly what axios's XHR adapter
|
|
39
|
-
* listens on.
|
|
40
|
-
*
|
|
41
|
-
* Several non-obvious behaviours are handled below; each one is a real bug if
|
|
42
|
-
* you skip it, and each is commented at the line that fixes it.
|
|
43
|
-
*/
|
|
44
|
-
|
|
45
|
-
const HEADERS_RECEIVED = 2;
|
|
46
|
-
const LOADING = 3;
|
|
47
|
-
const DONE = 4;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* The private surface of RN's XMLHttpRequest that we drive.
|
|
51
|
-
*
|
|
52
|
-
* Typed explicitly rather than reached for with `any` so that if a future React
|
|
53
|
-
* Native renames one of these, the compiler points at every use — and so the
|
|
54
|
-
* blast radius of "we depend on RN internals" is one interface.
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
const internalsOf = xhr => xhr;
|
|
58
|
-
let warnedUnsupported = false;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Can this XMLHttpRequest be driven through React Native's internals?
|
|
62
|
-
*
|
|
63
|
-
* The RN technique rests on those internals, so it is feature-detected rather
|
|
64
|
-
* than assumed. A request that fails this check is NOT automatically a lost
|
|
65
|
-
* cause — `canSynthesizeStandard` covers the standards XHR next.
|
|
66
|
-
*/
|
|
67
|
-
export function canSynthesize(xhr) {
|
|
68
|
-
const internals = internalsOf(xhr);
|
|
69
|
-
return typeof internals.setReadyState === "function" && typeof internals.setResponseHeaders === "function";
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Can this XMLHttpRequest be driven as a STANDARDS one?
|
|
74
|
-
*
|
|
75
|
-
* `dispatchEvent` is the load-bearing requirement: the whole standard path
|
|
76
|
-
* works by defining instance own-properties and then dispatching the
|
|
77
|
-
* lifecycle events through the XHR's own EventTarget. `removeEventListener`
|
|
78
|
-
* rules out half-mocks that could take the branch and then leak listeners.
|
|
79
|
-
*/
|
|
80
|
-
export function canSynthesizeStandard(xhr) {
|
|
81
|
-
return typeof xhr.addEventListener === "function" && typeof xhr.removeEventListener === "function" && typeof xhr.dispatchEvent === "function";
|
|
82
|
-
}
|
|
83
|
-
function warnUnsupported() {
|
|
84
|
-
if (warnedUnsupported) return;
|
|
85
|
-
warnedUnsupported = true;
|
|
86
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
87
|
-
console.warn("[Buoy] Network overrides need an XMLHttpRequest they can drive (React " + "Native's, or a standards EventTarget one) and this environment " + "provides neither — requests will run normally.");
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Synthesize a successful response. */
|
|
92
|
-
function respond(xhr, url, outcome) {
|
|
93
|
-
const internals = internalsOf(xhr);
|
|
94
|
-
|
|
95
|
-
// `_reset()` does `delete this.responseURL`, so `'responseURL' in xhr` is
|
|
96
|
-
// FALSE on a fresh request — and whatwg-fetch reads exactly that to populate
|
|
97
|
-
// `Response.url` (fetch.js:558). Without this line every overridden fetch
|
|
98
|
-
// response would silently carry `url: ""`.
|
|
99
|
-
internals.responseURL = url;
|
|
100
|
-
internals.status = outcome.status;
|
|
101
|
-
// RN has no `statusText` field at all (real requests report `undefined`), so
|
|
102
|
-
// this is a new own property. Harmless, and it makes the tool's list read
|
|
103
|
-
// correctly instead of showing a bare number.
|
|
104
|
-
internals.statusText = outcome.statusText;
|
|
105
|
-
internals.setResponseHeaders?.(outcome.headers);
|
|
106
|
-
// HEADERS_RECEIVED also stamps the interceptor's existing `_ttfb`, so an
|
|
107
|
-
// overridden request reports its injected latency like a real one.
|
|
108
|
-
internals.setReadyState?.(HEADERS_RECEIVED);
|
|
109
|
-
if (internals._aborted) return;
|
|
110
|
-
|
|
111
|
-
// whatwg-fetch sets `responseType = 'blob'` before every send
|
|
112
|
-
// (fetch.js:599-606), which would make RN's `response` getter demand a native
|
|
113
|
-
// Blob descriptor from BlobManager. But the polyfill reads the response
|
|
114
|
-
// exactly once — `'response' in xhr ? xhr.response : xhr.responseText`
|
|
115
|
-
// (fetch.js:559) — and never re-reads `responseType`. Handing back text is
|
|
116
|
-
// therefore both sufficient and strictly simpler: no Blob, no FileReader, no
|
|
117
|
-
// native round trip, and `.json()` becomes a synchronous JSON.parse.
|
|
118
|
-
//
|
|
119
|
-
// Assign the FIELD, not the property: the `responseType` setter throws once
|
|
120
|
-
// `_sent` is true (XMLHttpRequest.js:215), and we set `_sent` above.
|
|
121
|
-
internals._responseType = "text";
|
|
122
|
-
internals._response = outcome.body;
|
|
123
|
-
internals._cachedResponse = undefined; // force the getter to recompute
|
|
124
|
-
internals.setReadyState?.(LOADING);
|
|
125
|
-
if (internals._aborted) return;
|
|
126
|
-
internals.setReadyState?.(DONE); // dispatches 'load' then 'loadend'
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** Synthesize a transport failure — offline or timeout. */
|
|
130
|
-
function fail(xhr, outcome) {
|
|
131
|
-
const internals = internalsOf(xhr);
|
|
132
|
-
const timedOut = outcome.failKind === "timeout";
|
|
133
|
-
|
|
134
|
-
// These two flags are the entire difference between the 'error' and
|
|
135
|
-
// 'timeout' events — see `setReadyState` in XMLHttpRequest.js. whatwg-fetch
|
|
136
|
-
// turns them into `TypeError: Network request failed` and
|
|
137
|
-
// `TypeError: Network request timed out` respectively, which is exactly what
|
|
138
|
-
// the app would see from a real dead connection.
|
|
139
|
-
internals._hasError = true;
|
|
140
|
-
internals._timedOut = timedOut;
|
|
141
|
-
internals._responseType = "text";
|
|
142
|
-
internals._response = timedOut ? "Request timed out (Buoy override)" : "Network request failed (Buoy override)";
|
|
143
|
-
internals._cachedResponse = undefined;
|
|
144
|
-
internals.setReadyState?.(DONE);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ============================================================================
|
|
148
|
-
// STANDARDS XMLHttpRequest path (webview ports / react-native-web)
|
|
149
|
-
// ============================================================================
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Shadow a prototype accessor with an instance own-property.
|
|
153
|
-
*
|
|
154
|
-
* This is the entire trick: `xhr.status = 500` silently no-ops (or throws in
|
|
155
|
-
* strict mode) against the readonly getter on `XMLHttpRequest.prototype`, but
|
|
156
|
-
* an own DATA property on the instance is legal and takes precedence in every
|
|
157
|
-
* lookup. `configurable: true` so `readyState` can be redefined per
|
|
158
|
-
* transition. Works identically against RN's plain class fields, so nothing
|
|
159
|
-
* here is browser-only — the RN path just has a richer mechanism available.
|
|
160
|
-
*/
|
|
161
|
-
function defineOwn(xhr, name, value) {
|
|
162
|
-
Object.defineProperty(xhr, name, {
|
|
163
|
-
value,
|
|
164
|
-
configurable: true,
|
|
165
|
-
enumerable: true,
|
|
166
|
-
writable: false
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Build a lifecycle event to dispatch by hand.
|
|
172
|
-
*
|
|
173
|
-
* `ProgressEvent` where the spec uses one (load/loadend/error/timeout/abort)
|
|
174
|
-
* and the constructor exists; plain `Event` otherwise (Node test runs have no
|
|
175
|
-
* ProgressEvent); a `{ type }` literal as the last resort for event-target
|
|
176
|
-
* shims. Dispatching through the XHR's own EventTarget is what makes the
|
|
177
|
-
* `onload`/`onloadend`/`onreadystatechange` handler ATTRIBUTES fire too —
|
|
178
|
-
* they're listeners in the same list, which is exactly what axios's adapter
|
|
179
|
-
* registers.
|
|
180
|
-
*/
|
|
181
|
-
function makeEvent(type) {
|
|
182
|
-
if (type !== "readystatechange" && typeof ProgressEvent === "function") {
|
|
183
|
-
try {
|
|
184
|
-
return new ProgressEvent(type);
|
|
185
|
-
} catch {
|
|
186
|
-
// fall through
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (typeof Event === "function") {
|
|
190
|
-
try {
|
|
191
|
-
return new Event(type);
|
|
192
|
-
} catch {
|
|
193
|
-
// fall through
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
type
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
function fireEvent(xhr, type) {
|
|
201
|
-
xhr.dispatchEvent(makeEvent(type));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** Move the shadowed `readyState` and announce it — the interceptor's own
|
|
205
|
-
* listener stamps TTFB off the HEADERS_RECEIVED notification, same as a real
|
|
206
|
-
* response. */
|
|
207
|
-
function setStandardReadyState(xhr, state) {
|
|
208
|
-
defineOwn(xhr, "readyState", state);
|
|
209
|
-
fireEvent(xhr, "readystatechange");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* `xhr.response` in the caller's requested shape.
|
|
214
|
-
*
|
|
215
|
-
* A standards XHR types `response` off `responseType`; axios sets it when the
|
|
216
|
-
* caller asked for one (default '' → text). JSON is parsed (spec: null on
|
|
217
|
-
* parse failure), arraybuffer/blob are best-effort encodings of the rule's
|
|
218
|
-
* text body, everything else falls back to the string.
|
|
219
|
-
*/
|
|
220
|
-
function standardResponseFor(xhr, outcome) {
|
|
221
|
-
let responseType = "";
|
|
222
|
-
try {
|
|
223
|
-
responseType = xhr.responseType;
|
|
224
|
-
} catch {
|
|
225
|
-
// Some shims throw on access before send — treat as default text.
|
|
226
|
-
}
|
|
227
|
-
switch (responseType) {
|
|
228
|
-
case "":
|
|
229
|
-
case "text":
|
|
230
|
-
return outcome.body;
|
|
231
|
-
case "json":
|
|
232
|
-
try {
|
|
233
|
-
return JSON.parse(outcome.body);
|
|
234
|
-
} catch {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
case "arraybuffer":
|
|
238
|
-
if (typeof TextEncoder === "function") {
|
|
239
|
-
return new TextEncoder().encode(outcome.body).buffer;
|
|
240
|
-
}
|
|
241
|
-
return outcome.body;
|
|
242
|
-
case "blob":
|
|
243
|
-
if (typeof Blob === "function") {
|
|
244
|
-
const contentType = Object.entries(outcome.headers).find(([name]) => name.toLowerCase() === "content-type")?.[1] ?? "";
|
|
245
|
-
return new Blob([outcome.body], {
|
|
246
|
-
type: contentType
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
return outcome.body;
|
|
250
|
-
default:
|
|
251
|
-
return outcome.body;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** Synthesize a successful response on a standards XHR. */
|
|
256
|
-
function respondStandard(xhr, url, outcome, isAborted) {
|
|
257
|
-
const headers = outcome.headers;
|
|
258
|
-
// Spec shape: lowercase names, `name: value\r\n` per pair — axios splits on
|
|
259
|
-
// newlines and trims, raw XHR users get what a real response reads like.
|
|
260
|
-
const allHeaders = Object.entries(headers).map(([name, value]) => `${name.toLowerCase()}: ${value}\r\n`).join("");
|
|
261
|
-
defineOwn(xhr, "getAllResponseHeaders", () => allHeaders);
|
|
262
|
-
defineOwn(xhr, "getResponseHeader", name => {
|
|
263
|
-
const wanted = String(name).toLowerCase();
|
|
264
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
265
|
-
if (key.toLowerCase() === wanted) return value;
|
|
266
|
-
}
|
|
267
|
-
return null;
|
|
268
|
-
});
|
|
269
|
-
defineOwn(xhr, "responseURL", url);
|
|
270
|
-
defineOwn(xhr, "status", outcome.status);
|
|
271
|
-
defineOwn(xhr, "statusText", outcome.statusText);
|
|
272
|
-
defineOwn(xhr, "response", standardResponseFor(xhr, outcome));
|
|
273
|
-
// Own property, so it answers with the body even under a non-text
|
|
274
|
-
// `responseType` (where the real accessor would throw). axios reads it
|
|
275
|
-
// whenever `responseType` is '' or 'text'.
|
|
276
|
-
defineOwn(xhr, "responseText", outcome.body);
|
|
277
|
-
setStandardReadyState(xhr, HEADERS_RECEIVED);
|
|
278
|
-
if (isAborted()) return;
|
|
279
|
-
setStandardReadyState(xhr, LOADING);
|
|
280
|
-
if (isAborted()) return;
|
|
281
|
-
setStandardReadyState(xhr, DONE);
|
|
282
|
-
fireEvent(xhr, "load");
|
|
283
|
-
fireEvent(xhr, "loadend");
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/** Synthesize a transport failure on a standards XHR — offline or timeout. */
|
|
287
|
-
function failStandard(xhr, outcome) {
|
|
288
|
-
// `status` stays 0 (the prototype getter's answer for a request whose real
|
|
289
|
-
// send never ran) — exactly what a genuine network error reports. The
|
|
290
|
-
// 'error'/'timeout' event is the entire signal; axios turns them into
|
|
291
|
-
// ERR_NETWORK / ECONNABORTED the same way whatwg-fetch turns RN's flags
|
|
292
|
-
// into TypeErrors.
|
|
293
|
-
setStandardReadyState(xhr, DONE);
|
|
294
|
-
fireEvent(xhr, outcome.failKind === "timeout" ? "timeout" : "error");
|
|
295
|
-
fireEvent(xhr, "loadend");
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Apply an outcome to a standards XMLHttpRequest that has NOT been sent.
|
|
300
|
-
*
|
|
301
|
-
* The real `send()` is never invoked for respond/fail — the request must not
|
|
302
|
-
* touch the network. That leaves `abort()` with nothing to do natively (per
|
|
303
|
-
* spec, abort on a request whose send flag is unset dispatches NOTHING), so
|
|
304
|
-
* an instance shadow gives it the in-flight behaviour the app expects:
|
|
305
|
-
* cancel the pending outcome and dispatch abort + loadend. The shadow deletes
|
|
306
|
-
* itself the moment it can't matter anymore — after settling, and before a
|
|
307
|
-
* `delay` pass-through hands the request to the real network, where the
|
|
308
|
-
* prototype `abort()` must be reachable again.
|
|
309
|
-
*/
|
|
310
|
-
function runStandardOverride(xhr, url, outcome, passThrough) {
|
|
311
|
-
let timer = null;
|
|
312
|
-
let aborted = false;
|
|
313
|
-
let settled = false;
|
|
314
|
-
const restoreAbort = () => {
|
|
315
|
-
try {
|
|
316
|
-
delete xhr.abort;
|
|
317
|
-
} catch {
|
|
318
|
-
// Non-configurable shadow can't happen (we define it configurable), but
|
|
319
|
-
// never let cleanup throw into app code.
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
Object.defineProperty(xhr, "abort", {
|
|
323
|
-
configurable: true,
|
|
324
|
-
writable: true,
|
|
325
|
-
value: () => {
|
|
326
|
-
if (settled || aborted) return;
|
|
327
|
-
aborted = true;
|
|
328
|
-
settled = true;
|
|
329
|
-
if (timer !== null) {
|
|
330
|
-
clearTimeout(timer);
|
|
331
|
-
timer = null;
|
|
332
|
-
}
|
|
333
|
-
restoreAbort();
|
|
334
|
-
// The in-flight abort sequence: DONE, then 'abort', then 'loadend' —
|
|
335
|
-
// whatwg's request-error steps, which is also what RN's setReadyState
|
|
336
|
-
// dispatches off `_aborted`.
|
|
337
|
-
setStandardReadyState(xhr, DONE);
|
|
338
|
-
fireEvent(xhr, "abort");
|
|
339
|
-
fireEvent(xhr, "loadend");
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
const fire = () => {
|
|
343
|
-
timer = null;
|
|
344
|
-
if (aborted) return;
|
|
345
|
-
if (outcome.kind === "delay") {
|
|
346
|
-
// The real request is about to be genuinely in flight — put the
|
|
347
|
-
// prototype `abort()` back FIRST so cancelling reaches the network.
|
|
348
|
-
restoreAbort();
|
|
349
|
-
passThrough();
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (outcome.kind === "fail") {
|
|
353
|
-
failStandard(xhr, outcome);
|
|
354
|
-
} else {
|
|
355
|
-
respondStandard(xhr, url, outcome, () => aborted);
|
|
356
|
-
}
|
|
357
|
-
settled = true;
|
|
358
|
-
restoreAbort();
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
// ALWAYS asynchronous, even at 0ms — same contract as the RN path: callers
|
|
362
|
-
// legitimately attach handlers after `send()` returns (axios does).
|
|
363
|
-
timer = setTimeout(fire, outcome.delayMs);
|
|
364
|
-
return true;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// ============================================================================
|
|
368
|
-
// Entry point
|
|
369
|
-
// ============================================================================
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Apply an outcome to a request that has NOT been sent yet.
|
|
373
|
-
*
|
|
374
|
-
* Returns `false` when this environment can't be driven by hand, in which case
|
|
375
|
-
* the caller must send the request normally.
|
|
376
|
-
*
|
|
377
|
-
* @param passThrough Sends the real request. Only used by `kind: "delay"`.
|
|
378
|
-
*/
|
|
379
|
-
export function runOverride(xhr, url, outcome, passThrough) {
|
|
380
|
-
if (!canSynthesize(xhr)) {
|
|
381
|
-
// Not React Native's XMLHttpRequest — a standards one (webview port,
|
|
382
|
-
// react-native-web) is driven through instance property shadowing
|
|
383
|
-
// instead. Order matters: RN's XHR also extends an EventTarget shim, so
|
|
384
|
-
// the RN check must win first.
|
|
385
|
-
if (canSynthesizeStandard(xhr)) {
|
|
386
|
-
return runStandardOverride(xhr, url, outcome, passThrough);
|
|
387
|
-
}
|
|
388
|
-
warnUnsupported();
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
const internals = internalsOf(xhr);
|
|
392
|
-
|
|
393
|
-
// Claim the request as sent, for all three kinds.
|
|
394
|
-
//
|
|
395
|
-
// We skip RN's own `send()`, which is what normally sets this — and `abort()`
|
|
396
|
-
// branches on it: with `_sent` false it treats the request as never started,
|
|
397
|
-
// silently `_reset()`s, and dispatches NOTHING. The app's fetch promise would
|
|
398
|
-
// then never settle (a hang), and for a synthesized response our own timer
|
|
399
|
-
// would afterwards fire 'load' on a reset object, resolving a fetch the app
|
|
400
|
-
// had already aborted. Claiming it means abort() dispatches DONE + 'abort'
|
|
401
|
-
// and whatwg-fetch rejects with AbortError, as it should.
|
|
402
|
-
internals._sent = true;
|
|
403
|
-
|
|
404
|
-
// There is no native request to cancel until a delayed send is dispatched.
|
|
405
|
-
internals._requestId = null;
|
|
406
|
-
let timer = null;
|
|
407
|
-
const onAbort = () => {
|
|
408
|
-
xhr.removeEventListener("abort", onAbort);
|
|
409
|
-
if (timer !== null) {
|
|
410
|
-
clearTimeout(timer);
|
|
411
|
-
timer = null;
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
|
-
xhr.addEventListener("abort", onAbort);
|
|
415
|
-
const fire = () => {
|
|
416
|
-
timer = null;
|
|
417
|
-
xhr.removeEventListener("abort", onAbort);
|
|
418
|
-
// The real guard. `_aborted` is set unconditionally by `abort()` and
|
|
419
|
-
// survives its `_reset()`, so this is true whether or not the 'abort' event
|
|
420
|
-
// was ever dispatched.
|
|
421
|
-
if (internals._aborted) return;
|
|
422
|
-
if (outcome.kind === "delay") {
|
|
423
|
-
// Hand the state machine back before RN's `send()` sees it: it throws
|
|
424
|
-
// 'Request has already been sent' on a truthy `_sent`.
|
|
425
|
-
internals._sent = false;
|
|
426
|
-
passThrough();
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
if (outcome.kind === "fail") {
|
|
430
|
-
fail(xhr, outcome);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
respond(xhr, url, outcome);
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
// ALWAYS asynchronous, even at 0ms. Callers legitimately attach handlers
|
|
437
|
-
// after `send()` returns (axios does), and a synchronous response would fire
|
|
438
|
-
// 'load' before they exist.
|
|
439
|
-
timer = setTimeout(fire, outcome.delayMs);
|
|
440
|
-
return true;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/** Complete an already scheduled native outcome without adding another timer. */
|
|
444
|
-
export function completeNativeOverride(xhr, url, outcome) {
|
|
445
|
-
if (outcome.kind === "fail") fail(xhr, outcome);else if (outcome.kind === "respond") respond(xhr, url, outcome);
|
|
446
|
-
}
|
|
1
|
+
"use strict";import{realClearTimeout as k,realNow as _,realSetTimeout as U}from"../utils/realNow";const m=2;const P=3;const v=4;const R=e=>e;let D=false;export function canSynthesize(e){const n=R(e);return typeof n.setReadyState==="function"&&typeof n.setResponseHeaders==="function"}export function canSynthesizeStandard(e){return typeof e.addEventListener==="function"&&typeof e.removeEventListener==="function"&&typeof e.dispatchEvent==="function"}function A(){if(D)return;D=true;if(typeof __DEV__!=="undefined"&&__DEV__){console.warn("[Buoy] Network overrides need an XMLHttpRequest they can drive (React Native's, or a standards EventTarget one) and this environment provides neither \u2014 requests will run normally.")}}function H(e,n,t){const r=R(e);r.responseURL=n;r.status=t.status;r.statusText=t.statusText;r.setResponseHeaders?.(t.headers);r.setReadyState?.(m);if(r._aborted)return;r._responseType="text";r._response=t.body;r._cachedResponse=void 0;r.setReadyState?.(P);if(r._aborted)return;r.setReadyState?.(v)}function N(e,n){const t=R(e);const r=n.failKind==="timeout";t._hasError=true;t._timedOut=r;t._responseType="text";t._response=r?"Request timed out (Buoy override)":"Network request failed (Buoy override)";t._cachedResponse=void 0;t.setReadyState?.(v)}function f(e,n,t){Object.defineProperty(e,n,{value:t,configurable:true,enumerable:true,writable:false})}function K(e){if(e!=="readystatechange"&&typeof ProgressEvent==="function"){try{return new ProgressEvent(e)}catch{}}if(typeof Event==="function"){try{return new Event(e)}catch{}}return{type:e}}function c(e,n){e.dispatchEvent(K(n))}function E(e,n){f(e,"readyState",n);c(e,"readystatechange")}function I(e,n){let t="";try{t=e.responseType}catch{}switch(t){case"":case"text":return n.body;case"json":try{return JSON.parse(n.body)}catch{return null}case"arraybuffer":if(typeof TextEncoder==="function"){return new TextEncoder().encode(n.body).buffer}return n.body;case"blob":if(typeof Blob==="function"){const r=Object.entries(n.headers).find(([s])=>s.toLowerCase()==="content-type")?.[1]??"";return new Blob([n.body],{type:r})}return n.body;default:return n.body}}function V(e,n,t,r){const s=t.headers;const i=Object.entries(s).map(([a,o])=>`${a.toLowerCase()}: ${o}\r
|
|
2
|
+
`).join("");f(e,"getAllResponseHeaders",()=>i);f(e,"getResponseHeader",a=>{const o=String(a).toLowerCase();for(const[p,b]of Object.entries(s)){if(p.toLowerCase()===o)return b}return null});f(e,"responseURL",n);f(e,"status",t.status);f(e,"statusText",t.statusText);f(e,"response",I(e,t));f(e,"responseText",t.body);E(e,m);if(r())return;E(e,P);if(r())return;E(e,v);if(r())return;c(e,"load");c(e,"loadend")}function S(e,n){E(e,v);c(e,n.failKind==="timeout"?"timeout":"error");c(e,"loadend")}const y=new WeakMap;export function hasPendingStandardRequest(e){return y.has(e)}function z(e,n,t,r){const s=_();const i={};let a;let o;let p=false;let b=false;let g=false;let u=e.timeout;const M=e.abort;const q=e.open;const C=["abort","open","timeout","readyState","status","statusText","response","responseText","responseURL","getAllResponseHeaders","getResponseHeader"];const B=new Map(C.map(d=>[d,Object.getOwnPropertyDescriptor(e,d)]));let O=Object.getPrototypeOf(e);let w;while(O&&!w){w=Object.getOwnPropertyDescriptor(O,"timeout");O=Object.getPrototypeOf(O)}const l=()=>{p=true;if(y.get(e)===i)y.delete(e);clearTimeout(a);k(o);e.removeEventListener("loadend",l)};const L=()=>{l();for(const[d,j]of B){if(j)Object.defineProperty(e,d,j);else delete e[d]}e.timeout=u};const T=()=>{k(o);if(g){w?.set?.call(e,u>0?Math.max(1,u-(_()-s)):0)}else if(u>0){o=U(()=>{if(p)return;clearTimeout(a);S(e,{...t,kind:"fail",failKind:"timeout"});l()},Math.max(0,u-(_()-s)))}};Object.defineProperty(e,"timeout",{configurable:true,get:()=>u,set:d=>{u=Math.max(0,Number(d)||0);T()}});Object.defineProperty(e,"open",{configurable:true,value:(...d)=>{L();return Reflect.apply(q,e,d)}});Object.defineProperty(e,"abort",{configurable:true,value:()=>{if(g||p){L();M.call(e);return}b=true;clearTimeout(a);E(e,v);c(e,"abort");c(e,"loadend");l();if(!y.has(e))f(e,"readyState",0)}});y.set(e,i);e.addEventListener("loadend",l);T();a=setTimeout(()=>{if(p||b)return;if(t.kind==="delay"){g=true;T();try{r()}catch{S(e,{...t,kind:"fail",failKind:"network"});l()}return}if(t.kind==="fail")S(e,t);else V(e,n,t,()=>b||y.get(e)!==i);l()},t.delayMs);return true}export function runOverride(e,n,t,r){if(!canSynthesize(e)){if(canSynthesizeStandard(e)){return z(e,n,t,r)}A();return false}const s=R(e);s._sent=true;s._requestId=null;let i=null;const a=()=>{e.removeEventListener("abort",a);if(i!==null){clearTimeout(i);i=null}};e.addEventListener("abort",a);const o=()=>{i=null;e.removeEventListener("abort",a);if(s._aborted)return;if(t.kind==="delay"){s._sent=false;r();return}if(t.kind==="fail"){N(e,t);return}H(e,n,t)};i=setTimeout(o,t.delayMs);return true}export function completeNativeOverride(e,n,t){if(t.kind==="fail")N(e,t);else if(t.kind==="respond")H(e,n,t)}
|
|
@@ -1,85 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { hasAccountAccess } from "@buoy-gg/shared-ui";
|
|
4
|
-
/**
|
|
5
|
-
* The seam between the interceptor and the rule store.
|
|
6
|
-
*
|
|
7
|
-
* It exists to keep the import graph acyclic: `networkListener` needs rules,
|
|
8
|
-
* and the rule store needs the listener (to keep the swizzle installed while a
|
|
9
|
-
* rule is active). Rather than have them import each other, the store REGISTERS
|
|
10
|
-
* itself here and the listener asks here. Both sides import only this leaf.
|
|
11
|
-
*
|
|
12
|
-
* It's also the single place the production gate lives — see `overrideForRequest`.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { findMatchingRule, shouldApply, toOutcome } from "./resolveOverride";
|
|
16
|
-
let hooks = null;
|
|
17
|
-
export function setOverrideHooks(next) {
|
|
18
|
-
hooks = next;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Whether a rule stored right now could ever be applied to a request.
|
|
23
|
-
*
|
|
24
|
-
* `overrideForRequest` refuses in a release build, but every WRITE path
|
|
25
|
-
* (`upsertOverrideRule`, `setOverrideRuleEnabled`, `setOverridesEnabled`) still
|
|
26
|
-
* succeeds and still persists, so a remote caller was told `{ok: true}` for a
|
|
27
|
-
* rule that would never fire. That is fine for a human looking at the Network
|
|
28
|
-
* tool — they can see nothing is happening — and actively harmful for a remote
|
|
29
|
-
* driver relaying "done" to a QA tester, who then files a bug against data that
|
|
30
|
-
* was never actually faked.
|
|
31
|
-
*
|
|
32
|
-
* So the same gate is readable here and stamped onto those receipts. One
|
|
33
|
-
* predicate, one truth, at the same single entry point.
|
|
34
|
-
*/
|
|
35
|
-
export function overridesCanApply() {
|
|
36
|
-
// `__DEV__` is undefined outside React Native (unit tests, the desktop
|
|
37
|
-
// bundle); only an explicit `false` — a real release build — disables it.
|
|
38
|
-
return hasAccountAccess() && !(typeof __DEV__ !== "undefined" && !__DEV__);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Why overrides are inert, for a caller that has to explain it to a person. */
|
|
42
|
-
export const OVERRIDES_INACTIVE_REASON = "Response overrides never apply in a release build — the rule is saved but will not affect any request.";
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Diagnostics for the sync adapter's `debugOverrides` action.
|
|
46
|
-
*
|
|
47
|
-
* Reads the engine's own view of the world — crucially `hooks`, which is
|
|
48
|
-
* MODULE state here: if the interceptor and the rule store ever ended up with
|
|
49
|
-
* separate copies of this file, this is the only place that shows it.
|
|
50
|
-
*/
|
|
51
|
-
export function inspectEngine(url, method) {
|
|
52
|
-
return {
|
|
53
|
-
hooksInstalled: hooks !== null,
|
|
54
|
-
devFlag: typeof __DEV__ === "undefined" ? "undefined" : __DEV__,
|
|
55
|
-
ruleCount: hooks ? hooks.getRules().length : 0,
|
|
56
|
-
// Non-recording probe — a diagnostic must not burn a rule's `times` budget
|
|
57
|
-
// or nudge an alternating rule's phase.
|
|
58
|
-
matches: hooks ? findMatchingRule(url, method, hooks.getRules()) !== null : false
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Resolve an override for one outgoing request, recording the hit.
|
|
64
|
-
*
|
|
65
|
-
* NEVER ACTIVE IN A PRODUCTION BUILD. A shipped app that synthesizes 500s or
|
|
66
|
-
* silently swallows requests is a catastrophe of a different order than a
|
|
67
|
-
* broken dev tool, so the gate is here — at the single entry point — rather
|
|
68
|
-
* than trusted to every call site.
|
|
69
|
-
*/
|
|
70
|
-
export function overrideForRequest(url, method) {
|
|
71
|
-
if (!hooks) return null;
|
|
72
|
-
if (!overridesCanApply()) return null;
|
|
73
|
-
const rules = hooks.getRules();
|
|
74
|
-
if (rules.length === 0) return null;
|
|
75
|
-
const rule = findMatchingRule(url, method, rules);
|
|
76
|
-
if (!rule) return null;
|
|
77
|
-
|
|
78
|
-
// Phase is read BEFORE the match is recorded, so a fresh alternating rule
|
|
79
|
-
// (`seen === 0`) lets this first request through and takes the next one.
|
|
80
|
-
const applies = shouldApply(rule);
|
|
81
|
-
hooks.recordMatch(rule.id);
|
|
82
|
-
if (!applies) return null;
|
|
83
|
-
hooks.recordHit(rule.id);
|
|
84
|
-
return toOutcome(rule);
|
|
85
|
-
}
|
|
1
|
+
"use strict";import{hasAccountAccess as i}from"@buoy-gg/shared-ui";import{findMatchingRule as u,shouldApply as c,toOutcome as d}from"./resolveOverride";let e=null;export function setOverrideHooks(n){e=n}export function overridesCanApply(){return i()&&!(typeof __DEV__!=="undefined"&&!__DEV__)}export const OVERRIDES_INACTIVE_REASON="Response overrides never apply in a release build \u2014 the rule is saved but will not affect any request.";export function inspectEngine(n,r){return{hooksInstalled:e!==null,devFlag:typeof __DEV__==="undefined"?"undefined":__DEV__,ruleCount:e?e.getRules().length:0,matches:e?u(n,r,e.getRules())!==null:false}}export function overrideForRequest(n,r,o){if(!e)return null;if(!overridesCanApply())return null;const l=e.getRules();if(l.length===0)return null;const t=u(n,r,l,o);if(!t)return null;const s=c(t);e.recordMatch(t.id);if(!s)return null;e.recordHit(t.id);return d(t)}
|
|
@@ -1,75 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Glob matching for override rules — a faithful port of Chrome DevTools'.
|
|
5
|
-
*
|
|
6
|
-
* Ported from `NetworkPersistenceManager.ts:1051` + `StringUtilities.ts:9` in
|
|
7
|
-
* the devtools-frontend source. Ported rather than reinvented on purpose: `*`
|
|
8
|
-
* globs are the syntax developers already have in their fingers from Chrome's
|
|
9
|
-
* "Override headers" `applyTo` field, and a pattern that behaves differently
|
|
10
|
-
* here than it does in the browser would be a quiet trap.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Chrome's escape set, character for character.
|
|
15
|
-
*
|
|
16
|
-
* `*` is deliberately ABSENT — it survives escaping so it can become `.*`
|
|
17
|
-
* below. Everything else that means something to a regex is neutered.
|
|
18
|
-
*/
|
|
19
|
-
const SPECIAL_CHARACTERS = "[]{}()\\.^$+|-,?";
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Escape a glob into regex source: neutralize regex metacharacters, then
|
|
23
|
-
* promote `*` to `.*`.
|
|
24
|
-
*
|
|
25
|
-
* `split`/`join` rather than `replaceAll` — same result, no reliance on how
|
|
26
|
-
* complete a given Hermes build's ES2021 surface is.
|
|
27
|
-
*/
|
|
28
|
-
export function escapeRegex(pattern) {
|
|
29
|
-
let result = "";
|
|
30
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
31
|
-
const char = pattern.charAt(i);
|
|
32
|
-
if (SPECIAL_CHARACTERS.indexOf(char) !== -1) {
|
|
33
|
-
result += "\\";
|
|
34
|
-
}
|
|
35
|
-
result += char;
|
|
36
|
-
}
|
|
37
|
-
return result.split("*").join(".*");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Compiled patterns, cached by source.
|
|
42
|
-
*
|
|
43
|
-
* `resolveOverride` runs on EVERY request the app makes, against every rule.
|
|
44
|
-
* Recompiling a RegExp per request per rule is pure waste in the one place
|
|
45
|
-
* this feature is allowed to cost nothing.
|
|
46
|
-
*/
|
|
47
|
-
const compiled = new Map();
|
|
48
|
-
export function compilePattern(pattern) {
|
|
49
|
-
const cached = compiled.get(pattern);
|
|
50
|
-
if (cached) return cached;
|
|
51
|
-
// Anchored, like Chrome's `^${...}$` — a pattern describes the whole URL, so
|
|
52
|
-
// `pokeapi.co` matches nothing and `*pokeapi.co*` matches everything on that
|
|
53
|
-
// host. Predictable beats clever; the rule editor writes full URLs for you.
|
|
54
|
-
const regex = new RegExp(`^${escapeRegex(pattern)}$`);
|
|
55
|
-
// Unbounded growth isn't possible in practice (patterns come from a capped
|
|
56
|
-
// rule list), but a user editing a pattern character by character churns
|
|
57
|
-
// entries, so keep the cache from becoming a leak.
|
|
58
|
-
if (compiled.size > 200) compiled.clear();
|
|
59
|
-
compiled.set(pattern, regex);
|
|
60
|
-
return regex;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Does this rule apply to this request? Ignores `enabled` — callers check it. */
|
|
64
|
-
export function ruleMatches(rule, url, method) {
|
|
65
|
-
if (rule.methods && rule.methods.length > 0) {
|
|
66
|
-
if (!rule.methods.includes(method.toUpperCase())) return false;
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
return compilePattern(rule.urlPattern).test(url);
|
|
70
|
-
} catch {
|
|
71
|
-
// A pattern that can't compile matches nothing rather than throwing inside
|
|
72
|
-
// the app's `send()`. The rule editor validates; this is the backstop.
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
"use strict";const o="[]{}()\\.^$+|-,?";export function escapeRegex(e){let r="";for(let n=0;n<e.length;n++){const t=e.charAt(n);if(o.indexOf(t)!==-1){r+="\\"}r+=t}return r.split("*").join(".*")}const s=new Map;export function compilePattern(e){const r=s.get(e);if(r)return r;const n=e.startsWith("/")?`[a-zA-Z][a-zA-Z0-9+.-]*://[^/]*${escapeRegex(e)}`:escapeRegex(e);const t=new RegExp(`^${n}$`);if(s.size>200)s.clear();s.set(e,t);return t}function c(e,r){if(!e)return false;const n=r.toLowerCase();for(const t of Object.keys(e)){if(t.toLowerCase()===n&&e[t]!==void 0&&e[t]!=="")return true}return false}export function ruleMatches(e,r,n,t){if(e.methods&&e.methods.length>0){if(!e.methods.includes(n.toUpperCase()))return false}if(e.requireHeader&&!c(t,e.requireHeader))return false;try{return compilePattern(e.urlPattern).test(r)}catch{return false}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{ruleMatches as s}from"./matchRule";export function overriddenEvents(o,d){if(d.length===0)return[];const n=new Set(d.map(t=>t.id));const i=new Set;for(const t of d){let r;for(const e of o){if(e.override&&n.has(e.override.ruleId)){i.add(e.id);continue}if(!s(t,e.url,String(e.method||"GET"),e.requestHeaders))continue;if(e.timestamp>=t.createdAt)i.add(e.id);else if(!r||e.timestamp>r.timestamp)r=e}if(r)i.add(r.id)}return o.filter(t=>i.has(t.id))}
|