@capgo/inappbrowser 8.1.26 → 8.3.0-alpha.0

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 CHANGED
@@ -1,9 +1,22 @@
1
1
  # @capgo/inappbrowser
2
- <a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
2
+
3
+ <a href="https://capgo.app/">
4
+ <img
5
+ src="https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png"
6
+ alt="Capgo - Instant updates for capacitor"
7
+ />
8
+ </a>
3
9
 
4
10
  <div align="center">
5
- <h2><a href="https://capgo.app/?ref=plugin_inappbrowser"> ➡️ Get Instant updates for your App with Capgo</a></h2>
6
- <h2><a href="https://capgo.app/consulting/?ref=plugin_inappbrowser"> Missing a feature? We’ll build the plugin for you 💪</a></h2>
11
+ <h2>
12
+ <a href="https://capgo.app/?ref=plugin_inappbrowser"> ➡️ Get Instant updates for your App with Capgo</a>
13
+ </h2>
14
+ <h2>
15
+ <a href="https://capgo.app/consulting/?ref=plugin_inappbrowser">
16
+ {' '}
17
+ Missing a feature? We’ll build the plugin for you 💪
18
+ </a>
19
+ </h2>
7
20
  </div>
8
21
 
9
22
  Capacitor plugin in app browser with urlChangeEvent, two way communication, camera and microphone usage, etc.
@@ -30,10 +43,10 @@ The most complete doc is available here: https://capgo.app/docs/plugins/inappbro
30
43
 
31
44
  | Plugin version | Capacitor compatibility | Maintained |
32
45
  | -------------- | ----------------------- | ---------- |
33
- | v8.\*.\* | v8.\*.\* | ✅ |
34
- | v7.\*.\* | v7.\*.\* | On demand |
35
- | v6.\*.\* | v6.\*.\* | ❌ |
36
- | v5.\*.\* | v5.\*.\* | ❌ |
46
+ | v8.\*.\* | v8.\*.\* | ✅ |
47
+ | v7.\*.\* | v7.\*.\* | On demand |
48
+ | v6.\*.\* | v6.\*.\* | ❌ |
49
+ | v5.\*.\* | v5.\*.\* | ❌ |
37
50
 
38
51
  > **Note:** The major version of this plugin follows the major version of Capacitor. Use the version that matches your Capacitor installation (e.g., plugin v8 for Capacitor 8). Only the latest major version is actively maintained.
39
52
 
@@ -43,28 +56,50 @@ The most complete doc is available here: https://capgo.app/docs/plugins/inappbro
43
56
  npm install @capgo/inappbrowser
44
57
  npx cap sync
45
58
  ```
59
+
46
60
  ## Usage
47
61
 
62
+ ```js
63
+ import { InAppBrowser } from '@capgo/inappbrowser';
64
+
65
+ InAppBrowser.open({ url: 'YOUR_URL' });
66
+ ```
67
+
68
+ ### Customize Chrome Custom Tab Appearance (Android)
69
+
70
+ The `open()` method launches a Chrome Custom Tab on Android. You can customize its appearance to blend with your app:
71
+
48
72
  ```js
49
73
  import { InAppBrowser } from '@capgo/inappbrowser'
50
74
 
51
- InAppBrowser.open({ url: "YOUR_URL" });
75
+ InAppBrowser.open({
76
+ url: "https://example.com",
77
+ toolbarColor: "#1A1A2E", // Match your app's theme
78
+ showTitle: true, // Show page title instead of raw URL
79
+ showArrow: true, // Back arrow instead of X close icon
80
+ urlBarHidingEnabled: true, // Auto-hide URL bar on scroll
81
+ disableShare: true, // Remove share from overflow menu
82
+ disableBookmark: true, // Hide bookmark icon (undocumented, may break)
83
+ disableDownload: true, // Hide download icon (undocumented, may break)
84
+ });
52
85
  ```
53
86
 
87
+ All CCT options are Android-only and safely ignored on iOS. See [`OpenOptions`](#openoptions) for full documentation.
88
+
54
89
  ### Open WebView with Custom Dimensions
55
90
 
56
91
  By default, the webview opens in fullscreen. You can set custom dimensions to control the size and position:
57
92
 
58
93
  ```js
59
- import { InAppBrowser } from '@capgo/inappbrowser'
94
+ import { InAppBrowser } from '@capgo/inappbrowser';
60
95
 
61
96
  // Open with custom dimensions (400x600 at position 50,100)
62
97
  const { id } = await InAppBrowser.openWebView({
63
- url: "YOUR_URL",
98
+ url: 'YOUR_URL',
64
99
  width: 400,
65
100
  height: 600,
66
101
  x: 50,
67
- y: 100
102
+ y: 100,
68
103
  });
69
104
 
70
105
  // Update dimensions at runtime
@@ -73,7 +108,7 @@ InAppBrowser.updateDimensions({
73
108
  width: 500,
74
109
  height: 700,
75
110
  x: 100,
76
- y: 150
111
+ y: 150,
77
112
  });
78
113
  ```
79
114
 
@@ -84,11 +119,11 @@ InAppBrowser.updateDimensions({
84
119
  To create a webView with a 20px bottom margin (safe margin area outside the browser):
85
120
 
86
121
  ```js
87
- import { InAppBrowser } from '@capgo/inappbrowser'
122
+ import { InAppBrowser } from '@capgo/inappbrowser';
88
123
 
89
124
  InAppBrowser.openWebView({
90
- url: "YOUR_URL",
91
- enabledSafeBottomMargin: true
125
+ url: 'YOUR_URL',
126
+ enabledSafeBottomMargin: true,
92
127
  });
93
128
  ```
94
129
 
@@ -99,15 +134,16 @@ Web platform is not supported. Use `window.open` instead.
99
134
  To open the webview in true full screen mode (content extends behind the status bar), set `enabledSafeTopMargin` to `false`:
100
135
 
101
136
  ```js
102
- import { InAppBrowser } from '@capgo/inappbrowser'
137
+ import { InAppBrowser } from '@capgo/inappbrowser';
103
138
 
104
139
  InAppBrowser.openWebView({
105
- url: "YOUR_URL",
106
- enabledSafeTopMargin: false // Disables safe area at top, allows full screen
140
+ url: 'YOUR_URL',
141
+ enabledSafeTopMargin: false, // Disables safe area at top, allows full screen
107
142
  });
108
143
  ```
109
144
 
110
145
  This option works independently of the toolbar type:
146
+
111
147
  - **iOS**: The webview extends behind the status bar, providing true edge-to-edge content
112
148
  - **Android**: The top margin is disabled, allowing content to fill the entire screen
113
149
 
@@ -193,16 +229,16 @@ With this plugin you can send events from the main app to the inappbrowser and v
193
229
  #### Main app to inappbrowser, detail object is mendatory
194
230
 
195
231
  ```js
196
- const { id } = await InAppBrowser.openWebView({ url: "YOUR_URL" });
197
- InAppBrowser.postMessage({ id, detail: { message: "myMessage" } });
232
+ const { id } = await InAppBrowser.openWebView({ url: 'YOUR_URL' });
233
+ InAppBrowser.postMessage({ id, detail: { message: 'myMessage' } });
198
234
  // Or broadcast to all open webviews
199
- InAppBrowser.postMessage({ detail: { message: "broadcast" } });
235
+ InAppBrowser.postMessage({ detail: { message: 'broadcast' } });
200
236
  ```
201
237
 
202
238
  #### Receive event from native in the inappbrowser
203
239
 
204
240
  ```js
205
- window.addEventListener("messageFromNative", (event) => {
241
+ window.addEventListener('messageFromNative', (event) => {
206
242
  console.log(event);
207
243
  });
208
244
  ```
@@ -210,13 +246,13 @@ window.addEventListener("messageFromNative", (event) => {
210
246
  #### Send event from inappbrowser to main app, detail object is mendatory
211
247
 
212
248
  ```js
213
- window.mobileApp.postMessage({ detail: { message: "myMessage" } });
249
+ window.mobileApp.postMessage({ detail: { message: 'myMessage' } });
214
250
  ```
215
251
 
216
252
  #### Receive event from inappbrowser in the main app
217
253
 
218
254
  ```js
219
- InAppBrowser.addListener("messageFromWebview", (event) => {
255
+ InAppBrowser.addListener('messageFromWebview', (event) => {
220
256
  console.log(event.id, event.detail);
221
257
  });
222
258
  ```
@@ -251,6 +287,8 @@ window.mobileApp.close();
251
287
  * [`addListener('messageFromWebview', ...)`](#addlistenermessagefromwebview-)
252
288
  * [`addListener('browserPageLoaded', ...)`](#addlistenerbrowserpageloaded-)
253
289
  * [`addListener('pageLoadError', ...)`](#addlistenerpageloaderror-)
290
+ * [`addListener('proxyRequest', ...)`](#addlistenerproxyrequest-)
291
+ * [`handleProxyRequest(...)`](#handleproxyrequest)
254
292
  * [`removeAllListeners()`](#removealllisteners)
255
293
  * [`reload(...)`](#reload)
256
294
  * [`updateDimensions(...)`](#updatedimensions)
@@ -635,6 +673,45 @@ Will be triggered when page load error
635
673
  --------------------
636
674
 
637
675
 
676
+ ### addListener('proxyRequest', ...)
677
+
678
+ ```typescript
679
+ addListener(eventName: 'proxyRequest', listenerFunc: (event: ProxyRequest) => void) => Promise<PluginListenerHandle>
680
+ ```
681
+
682
+ Listen for proxied requests from the in-app browser webview.
683
+ Use addProxyHandler() wrapper instead of calling this directly.
684
+
685
+ | Param | Type |
686
+ | ------------------ | ------------------------------------------------------------------------- |
687
+ | **`eventName`** | <code>'proxyRequest'</code> |
688
+ | **`listenerFunc`** | <code>(event: <a href="#proxyrequest">ProxyRequest</a>) =&gt; void</code> |
689
+
690
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
691
+
692
+ **Since:** 9.0.0
693
+
694
+ --------------------
695
+
696
+
697
+ ### handleProxyRequest(...)
698
+
699
+ ```typescript
700
+ handleProxyRequest(options: { requestId: string; response: ProxyResponse | null; webviewId?: string; }) => Promise<void>
701
+ ```
702
+
703
+ Internal method: sends a proxied response back to native.
704
+ Called by addProxyHandler() wrapper — not intended for direct use.
705
+
706
+ | Param | Type |
707
+ | ------------- | --------------------------------------------------------------------------------------------------------------------- |
708
+ | **`options`** | <code>{ requestId: string; response: <a href="#proxyresponse">ProxyResponse</a> \| null; webviewId?: string; }</code> |
709
+
710
+ **Since:** 9.0.0
711
+
712
+ --------------------
713
+
714
+
638
715
  ### removeAllListeners()
639
716
 
640
717
  ```typescript
@@ -746,11 +823,18 @@ And in the AndroidManifest.xml file:
746
823
 
747
824
  #### OpenOptions
748
825
 
749
- | Prop | Type | Description | Since |
750
- | ---------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- | ----- |
751
- | **`url`** | <code>string</code> | Target URL to load. | 0.1.0 |
752
- | **`isPresentAfterPageLoad`** | <code>boolean</code> | if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | 0.1.0 |
753
- | **`preventDeeplink`** | <code>boolean</code> | if true the deeplink will not be opened, if false the deeplink will be opened when clicked on the link | 0.1.0 |
826
+ | Prop | Type | Description | Default | Since |
827
+ | ---------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
828
+ | **`url`** | <code>string</code> | Target URL to load. | | 0.1.0 |
829
+ | **`isPresentAfterPageLoad`** | <code>boolean</code> | if true, the browser will be presented after the page is loaded, if false, the browser will be presented immediately. | | 0.1.0 |
830
+ | **`preventDeeplink`** | <code>boolean</code> | if true the deeplink will not be opened, if false the deeplink will be opened when clicked on the link | | 0.1.0 |
831
+ | **`toolbarColor`** | <code>string</code> | Toolbar background color in hex format (e.g., "#1A1A2E"). Applied to both light and dark color schemes. Also sets the navigation bar color to match. **Android only** — ignored on iOS. | | 8.2.0 |
832
+ | **`urlBarHidingEnabled`** | <code>boolean</code> | Whether the URL bar should auto-hide when the user scrolls down. The bar reappears on any upward scroll. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
833
+ | **`showTitle`** | <code>boolean</code> | Show the page's HTML &lt;title&gt; in the toolbar instead of the raw URL. The true URL is still visible when the user taps the title area. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
834
+ | **`showArrow`** | <code>boolean</code> | Replace the default "X" close icon with a back arrow. Makes the Custom Tab feel like a native navigation push rather than a modal overlay. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
835
+ | **`disableShare`** | <code>boolean</code> | Remove the share action from the overflow menu. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
836
+ | **`disableBookmark`** | <code>boolean</code> | Hide the bookmark star icon in the overflow menu. Uses an undocumented Chromium intent extra — may stop working on future Chrome updates. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
837
+ | **`disableDownload`** | <code>boolean</code> | Hide the download icon in the overflow menu. Uses an undocumented Chromium intent extra — may stop working on future Chrome updates. **Android only** — ignored on iOS. | <code>false</code> | 8.2.0 |
754
838
 
755
839
 
756
840
  #### ClearCookieOptions
@@ -820,7 +904,7 @@ And in the AndroidManifest.xml file:
820
904
  | **`ignoreUntrustedSSLError`** | <code>boolean</code> | ignoreUntrustedSSLError: if true, the webview will ignore untrusted SSL errors allowing the user to view the website. | <code>false</code> | 6.1.0 |
821
905
  | **`preShowScript`** | <code>string</code> | preShowScript: if isPresentAfterPageLoad is true and this variable is set the plugin will inject a script before showing the browser. This script will be run in an async context. The plugin will wait for the script to finish (max 10 seconds) | | 6.6.0 |
822
906
  | **`preShowScriptInjectionTime`** | <code>'documentStart' \| 'pageLoad'</code> | preShowScriptInjectionTime: controls when the preShowScript is injected. - "documentStart": injects before any page JavaScript runs (good for polyfills like Firebase) - "pageLoad": injects after page load (default, original behavior) | <code>"pageLoad"</code> | 7.26.0 |
823
- | **`proxyRequests`** | <code>string</code> | proxyRequests is a regex expression. Please see [this pr](https://github.com/Cap-go/capacitor-inappbrowser/pull/222) for more info. (Android only) | | 6.9.0 |
907
+ | **`proxyRequests`** | <code>boolean</code> | When true, all HTTP/HTTPS requests from the webview are sent to the proxy handler registered via addProxyHandler(). The handler can return a custom Response or null for pass-through. | | 9.0.0 |
824
908
  | **`buttonNearDone`** | <code>{ ios: { iconType: 'sf-symbol' \| 'asset'; icon: string; }; android: { iconType: 'asset' \| 'vector'; icon: string; width?: number; height?: number; }; }</code> | buttonNearDone allows for a creation of a custom button near the done/close button. The button is only shown when toolbarType is not "activity", "navigation", or "blank". For Android: - iconType must be "asset" - icon path should be in the public folder (e.g. "monkey.svg") - width and height are optional, defaults to 48dp - button is positioned at the end of toolbar with 8dp margin For iOS: - iconType can be "sf-symbol" or "asset" - for sf-symbol, icon should be the symbol name - for asset, icon should be the asset name | | 6.7.0 |
825
909
  | **`textZoom`** | <code>number</code> | textZoom: sets the text zoom of the page in percent. Allows users to increase or decrease the text size for better readability. | <code>100</code> | 7.6.0 |
826
910
  | **`preventDeeplink`** | <code>boolean</code> | preventDeeplink: if true, the deeplink will not be opened, if false the deeplink will be opened when clicked on the link. on IOS each schema need to be added to info.plist file under LSApplicationQueriesSchemes when false to make it work. | <code>false</code> | 0.1.0 |
@@ -883,6 +967,31 @@ And in the AndroidManifest.xml file:
883
967
  | **`url`** | <code>string</code> | Emit when a button is clicked. | 0.0.1 |
884
968
 
885
969
 
970
+ #### ProxyRequest
971
+
972
+ Represents an intercepted HTTP request from the in-app browser webview.
973
+
974
+ | Prop | Type | Description |
975
+ | --------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
976
+ | **`requestId`** | <code>string</code> | Unique identifier for this request, used to match responses |
977
+ | **`url`** | <code>string</code> | The full URL being requested |
978
+ | **`method`** | <code>string</code> | HTTP method (GET, POST, PUT, DELETE, etc.) |
979
+ | **`headers`** | <code><a href="#record">Record</a>&lt;string, string&gt;</code> | Request headers as key-value pairs |
980
+ | **`body`** | <code>string \| null</code> | Base64-encoded request body, or null if no body. On Android, requests from HTML elements (img, script, link, iframe) are intercepted natively and do not have access to the request body — this field will be empty for those requests. Requests from fetch() and XMLHttpRequest include the full body. |
981
+ | **`webviewId`** | <code>string</code> | ID of the webview that made this request |
982
+
983
+
984
+ #### ProxyResponse
985
+
986
+ Response to send back for a proxied request.
987
+
988
+ | Prop | Type | Description |
989
+ | ------------- | --------------------------------------------------------------- | ----------------------------------- |
990
+ | **`body`** | <code>string</code> | Base64-encoded response body |
991
+ | **`status`** | <code>number</code> | HTTP status code |
992
+ | **`headers`** | <code><a href="#record">Record</a>&lt;string, string&gt;</code> | Response headers as key-value pairs |
993
+
994
+
886
995
  #### DimensionOptions
887
996
 
888
997
  | Prop | Type | Description |
@@ -996,5 +1105,6 @@ Construct a type with a set of properties K of type T
996
1105
  </docgen-api>
997
1106
 
998
1107
  **Credits**
999
- - [WKWebViewController](https://github.com/Meniny/WKWebViewController) - for iOS
1000
- - [CapBrowser](https://github.com/gadapa-rakesh/CapBrowser) - For the base in capacitor v2
1108
+
1109
+ - [WKWebViewController](https://github.com/Meniny/WKWebViewController) - for iOS
1110
+ - [CapBrowser](https://github.com/gadapa-rakesh/CapBrowser) - For the base in capacitor v2
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ (() => {
3
+ var __async = (__this, __arguments, generator) => {
4
+ return new Promise((resolve, reject) => {
5
+ var fulfilled = (value) => {
6
+ try {
7
+ step(generator.next(value));
8
+ } catch (e) {
9
+ reject(e);
10
+ }
11
+ };
12
+ var rejected = (value) => {
13
+ try {
14
+ step(generator.throw(value));
15
+ } catch (e) {
16
+ reject(e);
17
+ }
18
+ };
19
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
20
+ step((generator = generator.apply(__this, __arguments)).next());
21
+ });
22
+ };
23
+
24
+ // src/proxy-bridge.ts
25
+ (function() {
26
+ const proxyBridge = window.__capgoProxy;
27
+ if (!proxyBridge) return;
28
+ const accessToken = "___CAPGO_PROXY_TOKEN___";
29
+ let requestCounter = 0;
30
+ function generateRequestId() {
31
+ return "pr_" + Date.now() + "_" + requestCounter++;
32
+ }
33
+ function arrayBufferToBase64(buffer) {
34
+ const bytes = new Uint8Array(buffer);
35
+ let binary = "";
36
+ for (let i = 0; i < bytes.byteLength; i++) {
37
+ binary += String.fromCharCode(bytes[i]);
38
+ }
39
+ return btoa(binary);
40
+ }
41
+ function stringToBase64(str) {
42
+ return btoa(unescape(encodeURIComponent(str)));
43
+ }
44
+ function resolveUrl(url) {
45
+ if (url && !url.match(/^[a-zA-Z][a-zA-Z0-9+\-.]*:\/\//)) {
46
+ try {
47
+ return new URL(url, window.location.href).href;
48
+ } catch (_e) {
49
+ return url;
50
+ }
51
+ }
52
+ return url;
53
+ }
54
+ function bodyToBase64(body) {
55
+ return __async(this, null, function* () {
56
+ if (body === null || body === void 0) return null;
57
+ if (typeof body === "string") return stringToBase64(body);
58
+ if (body instanceof ArrayBuffer) return arrayBufferToBase64(body);
59
+ if (ArrayBuffer.isView(body))
60
+ return arrayBufferToBase64(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength));
61
+ if (body instanceof Blob) {
62
+ const ab = yield body.arrayBuffer();
63
+ return arrayBufferToBase64(ab);
64
+ }
65
+ if (body instanceof FormData) {
66
+ const ab = yield new Response(body).arrayBuffer();
67
+ return arrayBufferToBase64(ab);
68
+ }
69
+ if (body instanceof URLSearchParams) {
70
+ return stringToBase64(body.toString());
71
+ }
72
+ return null;
73
+ });
74
+ }
75
+ const originalFetch = window.fetch;
76
+ window.fetch = function(input, init) {
77
+ return __async(this, null, function* () {
78
+ const requestId = generateRequestId();
79
+ let url;
80
+ let method = "GET";
81
+ const headers = {};
82
+ let body = null;
83
+ if (input instanceof Request) {
84
+ url = input.url;
85
+ method = input.method;
86
+ input.headers.forEach((v, k) => {
87
+ headers[k] = v;
88
+ });
89
+ try {
90
+ const cloned = input.clone();
91
+ const ab = yield cloned.arrayBuffer();
92
+ if (ab.byteLength > 0) {
93
+ body = ab;
94
+ }
95
+ } catch (_e) {
96
+ }
97
+ } else {
98
+ url = input instanceof URL ? input.toString() : input;
99
+ }
100
+ url = resolveUrl(url);
101
+ if (init) {
102
+ if (init.method) method = init.method;
103
+ if (init.headers) {
104
+ const h = new Headers(init.headers);
105
+ h.forEach((v, k) => {
106
+ headers[k] = v;
107
+ });
108
+ }
109
+ if (init.body !== void 0) body = init.body;
110
+ }
111
+ if (body instanceof FormData) {
112
+ const encoded = new Response(body);
113
+ const ct = encoded.headers.get("content-type");
114
+ if (ct) {
115
+ Object.keys(headers).forEach((k) => {
116
+ if (k.toLowerCase() === "content-type") delete headers[k];
117
+ });
118
+ headers["content-type"] = ct;
119
+ }
120
+ body = yield encoded.arrayBuffer();
121
+ }
122
+ const base64Body = yield bodyToBase64(body);
123
+ proxyBridge.storeRequest(accessToken, requestId, method, JSON.stringify(headers), base64Body || "");
124
+ const proxyUrl = "/_capgo_proxy_?u=" + encodeURIComponent(url) + "&rid=" + requestId;
125
+ return originalFetch.call(window, proxyUrl, { method: "GET" });
126
+ });
127
+ };
128
+ const XHROpen = XMLHttpRequest.prototype.open;
129
+ const XHRSend = XMLHttpRequest.prototype.send;
130
+ const XHRSetHeader = XMLHttpRequest.prototype.setRequestHeader;
131
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
132
+ this.__proxyMethod = method;
133
+ this.__proxyUrl = resolveUrl(url instanceof URL ? url.toString() : url);
134
+ this.__proxyHeaders = {};
135
+ return XHROpen.apply(this, [method, url, ...rest]);
136
+ };
137
+ XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
138
+ if (this.__proxyHeaders) {
139
+ this.__proxyHeaders[name] = value;
140
+ }
141
+ return XHRSetHeader.call(this, name, value);
142
+ };
143
+ XMLHttpRequest.prototype.send = function(body) {
144
+ const xhr = this;
145
+ const requestId = generateRequestId();
146
+ const method = xhr.__proxyMethod || "GET";
147
+ const url = xhr.__proxyUrl || "";
148
+ const headers = xhr.__proxyHeaders || {};
149
+ function completeSend(base64Body) {
150
+ proxyBridge.storeRequest(accessToken, requestId, method, JSON.stringify(headers), base64Body);
151
+ const proxyUrl = "/_capgo_proxy_?u=" + encodeURIComponent(url) + "&rid=" + requestId;
152
+ XHROpen.call(xhr, "GET", proxyUrl, true);
153
+ XHRSend.call(xhr, null);
154
+ }
155
+ if (body === null || body === void 0) {
156
+ completeSend("");
157
+ return;
158
+ }
159
+ if (typeof body === "string") {
160
+ completeSend(stringToBase64(body));
161
+ return;
162
+ }
163
+ if (body instanceof ArrayBuffer) {
164
+ completeSend(arrayBufferToBase64(body));
165
+ return;
166
+ }
167
+ if (ArrayBuffer.isView(body)) {
168
+ completeSend(arrayBufferToBase64(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength)));
169
+ return;
170
+ }
171
+ if (body instanceof URLSearchParams) {
172
+ completeSend(stringToBase64(body.toString()));
173
+ return;
174
+ }
175
+ if (body instanceof Blob || body instanceof FormData) {
176
+ const encoded = new Response(body);
177
+ if (body instanceof FormData) {
178
+ const ct = encoded.headers.get("content-type");
179
+ if (ct) {
180
+ Object.keys(headers).forEach((k) => {
181
+ if (k.toLowerCase() === "content-type") delete headers[k];
182
+ });
183
+ headers["content-type"] = ct;
184
+ }
185
+ }
186
+ encoded.arrayBuffer().then((ab) => {
187
+ completeSend(arrayBufferToBase64(ab));
188
+ }).catch((_e) => {
189
+ console.error("[proxy-bridge] Failed to encode Blob/FormData body:", _e);
190
+ completeSend("");
191
+ });
192
+ return;
193
+ }
194
+ completeSend("");
195
+ };
196
+ })();
197
+ })();