Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: exposeInMainWorld allow to expose non-object APIs #26834

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/api/context-bridge.md
Expand Up @@ -44,19 +44,19 @@ The `contextBridge` module has the following methods:
### `contextBridge.exposeInMainWorld(apiKey, api)` _Experimental_

* `apiKey` String - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`.
* `api` Record<String, any> - Your API object, more information on what this API can be and how it works is available below.
* `api` any - Your API, more information on what this API can be and how it works is available below.

## Usage

### API Objects
### API

The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be an object
The `api` provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be a `Function`, `String`, `Number`, `Array`, `Boolean`, or an object
whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean`, or another nested object that meets the same conditions.

`Function` values are proxied to the other context and all other values are **copied** and **frozen**. Any data / primitives sent in
the API object become immutable and updates on either side of the bridge do not result in an update on the other side.
the API become immutable and updates on either side of the bridge do not result in an update on the other side.

An example of a complex API object is shown below:
An example of a complex API is shown below:

```javascript
const { contextBridge } = require('electron')
Expand Down
2 changes: 1 addition & 1 deletion lib/renderer/api/context-bridge.ts
Expand Up @@ -8,7 +8,7 @@ const checkContextIsolationEnabled = () => {
};

const contextBridge: Electron.ContextBridge = {
exposeInMainWorld: (key: string, api: Record<string, any>) => {
exposeInMainWorld: (key: string, api: any) => {
checkContextIsolationEnabled();
return binding.exposeAPIInMainWorld(key, api);
}
Expand Down
15 changes: 9 additions & 6 deletions shell/renderer/api/electron_api_context_bridge.cc
Expand Up @@ -513,11 +513,13 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
}
}

void ExposeAPIInMainWorld(const std::string& key,
v8::Local<v8::Object> api_object,
void ExposeAPIInMainWorld(v8::Isolate* isolate,
const std::string& key,
v8::Local<v8::Value> api,
gin_helper::Arguments* args) {
TRACE_EVENT1("electron", "ContextBridge::ExposeAPIInMainWorld", "key", key);
auto* render_frame = GetRenderFrame(api_object);

auto* render_frame = GetRenderFrame(isolate->GetCurrentContext()->Global());
CHECK(render_frame);
auto* frame = render_frame->GetWebFrame();
CHECK(frame);
Expand All @@ -539,12 +541,13 @@ void ExposeAPIInMainWorld(const std::string& key,
context_bridge::ObjectCache object_cache;
v8::Context::Scope main_context_scope(main_context);

v8::MaybeLocal<v8::Object> maybe_proxy = CreateProxyForAPI(
api_object, isolated_context, main_context, &object_cache, false, 0);
v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext(
isolated_context, main_context, api, &object_cache, false, 0);
if (maybe_proxy.IsEmpty())
return;
auto proxy = maybe_proxy.ToLocalChecked();
if (!DeepFreeze(proxy, main_context))
if (proxy->IsObject() && !proxy->IsTypedArray() &&
!DeepFreeze(v8::Local<v8::Object>::Cast(proxy), main_context))
return;

global.SetReadOnlyNonConfigurable(key, proxy);
Expand Down