Repository: electron/electron
Pull request: fix: missing `fetch`-dependent interfaces in Node.js

#### Description of Change

Closes https://github.com/electron/electron/issues/42381.
Refs https://github.com/electron/electron/pull/41710

Fixes an issue where `fetch` dependent interfaces in Node.js were not defined when `nodeIntegration` was enabled in some circumstances. I handled this partially in https://github.com/electron/electron/pull/41710/commits/9e4ae9c040763ff84e356c2bffd3076d9d5ad7b2, but the problem extended slightly further and the same approach needed to be taken for `FormData`, `Request`, etc.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: Fixed an issue where `fetch` dependent interfaces in Node.js were not defined when `nodeIntegration` was enabled in some circumstances.

Changed files:
filename: lib/node/init.ts
patch: @@ -3,8 +3,11 @@ import { wrapFsWithAsar } from './asar-fs-wrapper';
 wrapFsWithAsar(require('fs'));
 
 // See ElectronRendererClient::DidCreateScriptContext.
-if ((globalThis as any).blinkFetch) {
-  globalThis.fetch = (globalThis as any).blinkFetch;
+if ((globalThis as any).blinkfetch) {
+  const keys = ['fetch', 'Response', 'FormData', 'Request', 'Headers'];
+  for (const key of keys) {
+    (globalThis as any)[key] = (globalThis as any)[`blink${key}`];
+  }
 }
 
 // Hook child_process.fork.

filename: shell/renderer/electron_renderer_client.cc
patch: @@ -110,19 +110,25 @@ void ElectronRendererClient::DidCreateScriptContext(
       base::BindRepeating(&ElectronRendererClient::UndeferLoad,
                           base::Unretained(this), render_frame));
 
-  v8::Local<v8::Object> global = renderer_context->Global();
-  v8::MaybeLocal<v8::Value> fetch =
-      global->Get(renderer_context, gin::StringToV8(env->isolate(), "fetch"));
-
   // We need to use the Blink implementation of fetch in the renderer process
   // Node.js deletes the global fetch function when their fetch implementation
   // is disabled, so we need to save and re-add it after the Node.js environment
   // is loaded. See corresponding change in node/init.ts.
-  if (!fetch.IsEmpty()) {
-    global
-        ->Set(renderer_context, gin::StringToV8(env->isolate(), "blinkFetch"),
-              fetch.ToLocalChecked())
-        .Check();
+  v8::Isolate* isolate = env->isolate();
+  v8::Local<v8::Object> global = renderer_context->Global();
+
+  std::vector<std::string> keys = {"fetch", "Response", "FormData", "Request",
+                                   "Headers"};
+  for (const auto& key : keys) {
+    v8::MaybeLocal<v8::Value> value =
+        global->Get(renderer_context, gin::StringToV8(isolate, key.c_str()));
+    if (!value.IsEmpty()) {
+      std::string blink_key = "blink" + key;
+      global
+          ->Set(renderer_context, gin::StringToV8(isolate, blink_key.c_str()),
+                value.ToLocalChecked())
+          .Check();
+    }
   }
 
   // If we have disabled the site instance overrides we should prevent loading