electron-wcap 1.0.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/LICENSE +21 -0
- package/README.md +112 -0
- package/common/declaration.d.ts +8 -0
- package/common/declaration.d.ts.map +1 -0
- package/common/errors.d.ts +9 -0
- package/common/errors.d.ts.map +1 -0
- package/common/errors.js +35 -0
- package/common/errors.js.map +1 -0
- package/common/interfaces.d.ts +4 -0
- package/common/interfaces.d.ts.map +1 -0
- package/common/protocol.d.ts +11 -0
- package/common/protocol.d.ts.map +1 -0
- package/common/protocol.js +13 -0
- package/common/protocol.js.map +1 -0
- package/esm/common/declaration.d.ts +8 -0
- package/esm/common/declaration.d.ts.map +1 -0
- package/esm/common/errors.d.ts +9 -0
- package/esm/common/errors.d.ts.map +1 -0
- package/esm/common/errors.js +29 -0
- package/esm/common/errors.js.map +1 -0
- package/esm/common/interfaces.d.ts +4 -0
- package/esm/common/interfaces.d.ts.map +1 -0
- package/esm/common/protocol.d.ts +11 -0
- package/esm/common/protocol.d.ts.map +1 -0
- package/esm/common/protocol.js +11 -0
- package/esm/common/protocol.js.map +1 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +4 -0
- package/esm/index.js.map +1 -0
- package/esm/main/callback-registry.d.ts +10 -0
- package/esm/main/callback-registry.d.ts.map +1 -0
- package/esm/main/callback-registry.js +59 -0
- package/esm/main/callback-registry.js.map +1 -0
- package/esm/main/index.d.ts +3 -0
- package/esm/main/index.d.ts.map +1 -0
- package/esm/main/index.js +2 -0
- package/esm/main/index.js.map +1 -0
- package/esm/main/injectable.d.ts +3 -0
- package/esm/main/injectable.d.ts.map +1 -0
- package/esm/main/injectable.js +30 -0
- package/esm/main/injectable.js.map +1 -0
- package/esm/main/provider.d.ts +7 -0
- package/esm/main/provider.d.ts.map +1 -0
- package/esm/main/provider.js +73 -0
- package/esm/main/provider.js.map +1 -0
- package/esm/package.json +1 -0
- package/esm/preload/bridge.d.ts +2 -0
- package/esm/preload/bridge.d.ts.map +1 -0
- package/esm/preload/bridge.js +17 -0
- package/esm/preload/bridge.js.map +1 -0
- package/esm/preload/index.d.ts +2 -0
- package/esm/preload/index.d.ts.map +1 -0
- package/esm/preload/index.js +2 -0
- package/esm/preload/index.js.map +1 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -0
- package/index.js +4 -0
- package/index.js.map +1 -0
- package/main/callback-registry.d.ts +10 -0
- package/main/callback-registry.d.ts.map +1 -0
- package/main/callback-registry.js +60 -0
- package/main/callback-registry.js.map +1 -0
- package/main/index.d.ts +3 -0
- package/main/index.d.ts.map +1 -0
- package/main/index.js +6 -0
- package/main/index.js.map +1 -0
- package/main/injectable.d.ts +3 -0
- package/main/injectable.d.ts.map +1 -0
- package/main/injectable.js +31 -0
- package/main/injectable.js.map +1 -0
- package/main/provider.d.ts +7 -0
- package/main/provider.d.ts.map +1 -0
- package/main/provider.js +73 -0
- package/main/provider.js.map +1 -0
- package/package.json +43 -0
- package/preload/bridge.d.ts +2 -0
- package/preload/bridge.d.ts.map +1 -0
- package/preload/bridge.js +17 -0
- package/preload/bridge.js.map +1 -0
- package/preload/index.d.ts +2 -0
- package/preload/index.d.ts.map +1 -0
- package/preload/index.js +6 -0
- package/preload/index.js.map +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Egor Kushnarev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# electron-wcap
|
|
2
|
+
|
|
3
|
+
Electron **W**eb**C**ontent **A**PI **P**rovider — call renderer APIs from the main process with support for passing callbacks.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
electron-wcap lets the main process use an API object that lives in a renderer (a `WebContents`). You get a typed proxy in the main process; calling a method runs the corresponding function in the renderer via injected script. Functions you pass as arguments are registered and bridged so the renderer can invoke them back into the main process.
|
|
8
|
+
|
|
9
|
+
- **Main process**: create a provider for a given `WebContents` and API key; use it like a normal async API.
|
|
10
|
+
- **Preload**: expose the callback bridge so renderer code can invoke those callbacks.
|
|
11
|
+
- **Renderer**: assign your API object to `window[apiKey]` and use it as usual.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm add electron-wcap
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Requires **Electron** (peer dependency). Node 22+ and pnpm are recommended (see `volta` in `package.json`).
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### 1. Main process
|
|
24
|
+
|
|
25
|
+
Import from `electron-wcap/main` and create a provider for a `WebContents` and a string `apiKey` that the renderer will use for the same API:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createApiProvider } from 'electron-wcap/main';
|
|
29
|
+
|
|
30
|
+
// e.g. after creating a BrowserWindow
|
|
31
|
+
const provider = createApiProvider<MyApi>(win.webContents, 'myApi');
|
|
32
|
+
|
|
33
|
+
function onData(data: unknown): void {
|
|
34
|
+
// This callback runs in the main process when the renderer calls it
|
|
35
|
+
console.log('Renderer sent:', data);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Call renderer methods (return value is a Promise)
|
|
39
|
+
const result = await provider.someMethod('arg', onData);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- The generic `MyApi` is for typing only; the real implementation lives in the renderer.
|
|
43
|
+
- Callbacks must be **named functions** (used as registry keys).
|
|
44
|
+
|
|
45
|
+
### 2. Preload
|
|
46
|
+
|
|
47
|
+
Import from `electron-wcap/preload` and enable the callback bridge so the renderer can invoke callbacks passed from main:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { enableCallbacks } from 'electron-wcap/preload';
|
|
51
|
+
|
|
52
|
+
enableCallbacks();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Load this script as the preload for any window whose renderer API you use with `createApiProvider`.
|
|
56
|
+
|
|
57
|
+
### 3. Renderer - optional
|
|
58
|
+
|
|
59
|
+
Expose your API on `window` under the same `apiKey` you used in `createApiProvider`:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const apiKey = 'myApi';
|
|
63
|
+
|
|
64
|
+
window[apiKey] = {
|
|
65
|
+
someMethod(arg: string, callback: (data: unknown) => void) {
|
|
66
|
+
// callback is a function that runs in the main process
|
|
67
|
+
callback({ received: arg });
|
|
68
|
+
return 'done';
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The renderer can call the callback (possibly asynchronously); the call is sent to the main process via IPC and the registered function runs there.
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### Main (`electron-wcap/main`)
|
|
78
|
+
|
|
79
|
+
- **`createApiProvider<ApiInterface>(webContents, apiKey)`**
|
|
80
|
+
Returns a proxy that implements `ApiInterface` (and `Promisify<ApiInterface>` so methods are async). Each property access returns an async function that runs the corresponding method in the renderer via `webContents.executeJavaScript`.
|
|
81
|
+
The proxy also has a readonly **`webContents`** property (the `WebContents` you passed in).
|
|
82
|
+
|
|
83
|
+
### Preload (`electron-wcap/preload`)
|
|
84
|
+
|
|
85
|
+
- **`enableCallbacks()`**
|
|
86
|
+
Exposes `__ElectronWCAPBridge__` on the renderer’s `window` via `contextBridge`, so renderer code can invoke callbacks that were passed from the main process.
|
|
87
|
+
|
|
88
|
+
### Important
|
|
89
|
+
|
|
90
|
+
- **Entry points**: Use `electron-wcap/main` in the main process and `electron-wcap/preload` in the preload script. Importing from `electron-wcap` alone throws an error that explains this.
|
|
91
|
+
- **Callback names**: Callbacks you pass from main must be named (e.g. `function onData(x) { ... }`), not anonymous, so they can be registered and invoked by name.
|
|
92
|
+
- **sandbox**: as Electron now deafult sandbox to `true`, you should disable sandoxing to use callbacks.
|
|
93
|
+
|
|
94
|
+
## Build
|
|
95
|
+
|
|
96
|
+
From the repo:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pnpm i
|
|
100
|
+
pnpm build
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Output: `dist/` (CommonJS) and `dist/esm/` (ESM).
|
|
104
|
+
|
|
105
|
+
## Scripts
|
|
106
|
+
|
|
107
|
+
- `pnpm build` — Rollup build (CJS + ESM)
|
|
108
|
+
- `pnpm lint` — Lint (editorconfig + ESLint)
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
See [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration.d.ts","sourceRoot":"","sources":["../../src/common/declaration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;QAEnB,sBAAsB,EAAE,cAAc,CAAC;KACvC;CACD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function unknownOptionsType(): Error;
|
|
2
|
+
export declare function apiKeyNotExists(apiKey: string, webContentsId: number): Error;
|
|
3
|
+
export declare function callbackNotRegistered(method: string, senderId: number): Error;
|
|
4
|
+
export declare function nonInvocationRequest(): Error;
|
|
5
|
+
export declare function callbackWithoutName(): Error;
|
|
6
|
+
export declare function callbackRegisteredAlready(callbackName: string, webContentsId: number): Error;
|
|
7
|
+
export declare function bridgeNotRegistered(): Error;
|
|
8
|
+
export declare function exportFromRoot(): Error;
|
|
9
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/common/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,IAAI,KAAK,CAE1C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAE7E;AAED,wBAAgB,oBAAoB,IAAI,KAAK,CAE5C;AAED,wBAAgB,mBAAmB,IAAI,KAAK,CAE3C;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,CAE5F;AAED,wBAAgB,mBAAmB,IAAI,KAAK,CAE3C;AAED,wBAAgB,cAAc,IAAI,KAAK,CAOtC"}
|
package/common/errors.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function apiKeyNotExists(apiKey, webContentsId) {
|
|
2
|
+
return Error(`electron-wcap: api with key '${apiKey}' does not exists in host with id '${webContentsId}'`);
|
|
3
|
+
}
|
|
4
|
+
function callbackNotRegistered(method, senderId) {
|
|
5
|
+
return Error(`electron-wcap: callback '${method}' is not registered in host '${senderId}'`);
|
|
6
|
+
}
|
|
7
|
+
function nonInvocationRequest() {
|
|
8
|
+
return Error('electron-wcap: got non callback invocation request');
|
|
9
|
+
}
|
|
10
|
+
function callbackWithoutName() {
|
|
11
|
+
return Error('electron-wcap: callback must have a name - use function decration syntax');
|
|
12
|
+
}
|
|
13
|
+
function callbackRegisteredAlready(callbackName, webContentsId) {
|
|
14
|
+
return Error(`electron-wcap: callback with name '${callbackName}' already registered in host with id '${webContentsId}'`);
|
|
15
|
+
}
|
|
16
|
+
function bridgeNotRegistered() {
|
|
17
|
+
return Error('electron-wcap: __ApiProviderBridge__ does not exists; make sure you have expose it via preload');
|
|
18
|
+
}
|
|
19
|
+
function exportFromRoot() {
|
|
20
|
+
return Error(`electron-wcap uses different code for the main and preload processes:
|
|
21
|
+
|
|
22
|
+
In the Electron main process you should import 'electron-wcap/main'
|
|
23
|
+
In the Electron preload you should import 'electron-wcap/preload'
|
|
24
|
+
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.apiKeyNotExists = apiKeyNotExists;
|
|
29
|
+
exports.bridgeNotRegistered = bridgeNotRegistered;
|
|
30
|
+
exports.callbackNotRegistered = callbackNotRegistered;
|
|
31
|
+
exports.callbackRegisteredAlready = callbackRegisteredAlready;
|
|
32
|
+
exports.callbackWithoutName = callbackWithoutName;
|
|
33
|
+
exports.exportFromRoot = exportFromRoot;
|
|
34
|
+
exports.nonInvocationRequest = nonInvocationRequest;
|
|
35
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../../src/common/errors.ts"],"sourcesContent":[null],"names":[],"mappings":"AAIM,SAAU,eAAe,CAAC,MAAc,EAAE,aAAqB,EAAA;IACpE,OAAO,KAAK,CAAC,CAAA,6BAAA,EAAiC,MAAO,sCAAuC,aAAc,CAAA,CAAA,CAAG,CAAC;AAC/G;AAEM,SAAU,qBAAqB,CAAC,MAAc,EAAE,QAAgB,EAAA;IACrE,OAAO,KAAK,CAAC,CAAA,yBAAA,EAA6B,MAAO,gCAAiC,QAAS,CAAA,CAAA,CAAG,CAAC;AAChG;SAEgB,oBAAoB,GAAA;AACnC,IAAA,OAAO,KAAK,CAAC,oDAAoD,CAAC;AACnE;SAEgB,mBAAmB,GAAA;AAClC,IAAA,OAAO,KAAK,CAAC,0EAA0E,CAAC;AACzF;AAEM,SAAU,yBAAyB,CAAC,YAAoB,EAAE,aAAqB,EAAA;IACpF,OAAO,KAAK,CAAC,CAAA,mCAAA,EAAuC,YAAa,yCAA0C,aAAc,CAAA,CAAA,CAAG,CAAC;AAC9H;SAEgB,mBAAmB,GAAA;AAClC,IAAA,OAAO,KAAK,CAAC,gGAAgG,CAAC;AAC/G;SAEgB,cAAc,GAAA;AAC7B,IAAA,OAAO,KAAK,CAAC,CAAA;;;;;AAKX,EAAA,CAAA,CAAC;AACJ;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/common/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;CAC1D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CallbackInvokeRequest {
|
|
2
|
+
method: string;
|
|
3
|
+
args: unknown[];
|
|
4
|
+
}
|
|
5
|
+
export interface DispatchedCallback {
|
|
6
|
+
dispatchedCallbackName: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isCallbackInvokeRequest(msg: unknown): msg is CallbackInvokeRequest;
|
|
9
|
+
export declare const BRIDGE_INVOKE_REQUEST_CHANNEL = "api-provider:bridge-request";
|
|
10
|
+
export declare const CALLBACK_BRIDGE_NAME = "__ElectronWCAPBridge__";
|
|
11
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/common/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IAClC,sBAAsB,EAAE,MAAM,CAAA;CAC9B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,qBAAqB,CAMlF;AAED,eAAO,MAAM,6BAA6B,gCAAgC,CAAC;AAE3E,eAAO,MAAM,oBAAoB,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function isCallbackInvokeRequest(msg) {
|
|
2
|
+
const mayBeRequest = msg;
|
|
3
|
+
return mayBeRequest !== null &&
|
|
4
|
+
typeof mayBeRequest.method === 'string' &&
|
|
5
|
+
Array.isArray(mayBeRequest.args);
|
|
6
|
+
}
|
|
7
|
+
const BRIDGE_INVOKE_REQUEST_CHANNEL = 'api-provider:bridge-request';
|
|
8
|
+
const CALLBACK_BRIDGE_NAME = '__ElectronWCAPBridge__';
|
|
9
|
+
|
|
10
|
+
exports.BRIDGE_INVOKE_REQUEST_CHANNEL = BRIDGE_INVOKE_REQUEST_CHANNEL;
|
|
11
|
+
exports.CALLBACK_BRIDGE_NAME = CALLBACK_BRIDGE_NAME;
|
|
12
|
+
exports.isCallbackInvokeRequest = isCallbackInvokeRequest;
|
|
13
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sources":["../../src/common/protocol.ts"],"sourcesContent":[null],"names":[],"mappings":"AASM,SAAU,uBAAuB,CAAC,GAAY,EAAA;IACnD,MAAM,YAAY,GAAG,GAA4B;IAEjD,OAAO,YAAY,KAAK,IAAI;AAC3B,QAAA,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ;AACvC,QAAA,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AAClC;AAEO,MAAM,6BAA6B,GAAG;AAEtC,MAAM,oBAAoB,GAAG;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration.d.ts","sourceRoot":"","sources":["../../../src/common/declaration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;QAEnB,sBAAsB,EAAE,cAAc,CAAC;KACvC;CACD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function unknownOptionsType(): Error;
|
|
2
|
+
export declare function apiKeyNotExists(apiKey: string, webContentsId: number): Error;
|
|
3
|
+
export declare function callbackNotRegistered(method: string, senderId: number): Error;
|
|
4
|
+
export declare function nonInvocationRequest(): Error;
|
|
5
|
+
export declare function callbackWithoutName(): Error;
|
|
6
|
+
export declare function callbackRegisteredAlready(callbackName: string, webContentsId: number): Error;
|
|
7
|
+
export declare function bridgeNotRegistered(): Error;
|
|
8
|
+
export declare function exportFromRoot(): Error;
|
|
9
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/common/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,IAAI,KAAK,CAE1C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAE7E;AAED,wBAAgB,oBAAoB,IAAI,KAAK,CAE5C;AAED,wBAAgB,mBAAmB,IAAI,KAAK,CAE3C;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,CAE5F;AAED,wBAAgB,mBAAmB,IAAI,KAAK,CAE3C;AAED,wBAAgB,cAAc,IAAI,KAAK,CAOtC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function apiKeyNotExists(apiKey, webContentsId) {
|
|
2
|
+
return Error(`electron-wcap: api with key '${apiKey}' does not exists in host with id '${webContentsId}'`);
|
|
3
|
+
}
|
|
4
|
+
function callbackNotRegistered(method, senderId) {
|
|
5
|
+
return Error(`electron-wcap: callback '${method}' is not registered in host '${senderId}'`);
|
|
6
|
+
}
|
|
7
|
+
function nonInvocationRequest() {
|
|
8
|
+
return Error('electron-wcap: got non callback invocation request');
|
|
9
|
+
}
|
|
10
|
+
function callbackWithoutName() {
|
|
11
|
+
return Error('electron-wcap: callback must have a name - use function decration syntax');
|
|
12
|
+
}
|
|
13
|
+
function callbackRegisteredAlready(callbackName, webContentsId) {
|
|
14
|
+
return Error(`electron-wcap: callback with name '${callbackName}' already registered in host with id '${webContentsId}'`);
|
|
15
|
+
}
|
|
16
|
+
function bridgeNotRegistered() {
|
|
17
|
+
return Error('electron-wcap: __ApiProviderBridge__ does not exists; make sure you have expose it via preload');
|
|
18
|
+
}
|
|
19
|
+
function exportFromRoot() {
|
|
20
|
+
return Error(`electron-wcap uses different code for the main and preload processes:
|
|
21
|
+
|
|
22
|
+
In the Electron main process you should import 'electron-wcap/main'
|
|
23
|
+
In the Electron preload you should import 'electron-wcap/preload'
|
|
24
|
+
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { apiKeyNotExists, bridgeNotRegistered, callbackNotRegistered, callbackRegisteredAlready, callbackWithoutName, exportFromRoot, nonInvocationRequest };
|
|
29
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../../../../src/common/errors.ts"],"sourcesContent":[null],"names":[],"mappings":"AAIM,SAAU,eAAe,CAAC,MAAc,EAAE,aAAqB,EAAA;IACpE,OAAO,KAAK,CAAC,CAAA,6BAAA,EAAiC,MAAO,sCAAuC,aAAc,CAAA,CAAA,CAAG,CAAC;AAC/G;AAEM,SAAU,qBAAqB,CAAC,MAAc,EAAE,QAAgB,EAAA;IACrE,OAAO,KAAK,CAAC,CAAA,yBAAA,EAA6B,MAAO,gCAAiC,QAAS,CAAA,CAAA,CAAG,CAAC;AAChG;SAEgB,oBAAoB,GAAA;AACnC,IAAA,OAAO,KAAK,CAAC,oDAAoD,CAAC;AACnE;SAEgB,mBAAmB,GAAA;AAClC,IAAA,OAAO,KAAK,CAAC,0EAA0E,CAAC;AACzF;AAEM,SAAU,yBAAyB,CAAC,YAAoB,EAAE,aAAqB,EAAA;IACpF,OAAO,KAAK,CAAC,CAAA,mCAAA,EAAuC,YAAa,yCAA0C,aAAc,CAAA,CAAA,CAAG,CAAC;AAC9H;SAEgB,mBAAmB,GAAA;AAClC,IAAA,OAAO,KAAK,CAAC,gGAAgG,CAAC;AAC/G;SAEgB,cAAc,GAAA;AAC7B,IAAA,OAAO,KAAK,CAAC,CAAA;;;;;AAKX,EAAA,CAAA,CAAC;AACJ;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../../src/common/interfaces.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;CAC1D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CallbackInvokeRequest {
|
|
2
|
+
method: string;
|
|
3
|
+
args: unknown[];
|
|
4
|
+
}
|
|
5
|
+
export interface DispatchedCallback {
|
|
6
|
+
dispatchedCallbackName: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isCallbackInvokeRequest(msg: unknown): msg is CallbackInvokeRequest;
|
|
9
|
+
export declare const BRIDGE_INVOKE_REQUEST_CHANNEL = "api-provider:bridge-request";
|
|
10
|
+
export declare const CALLBACK_BRIDGE_NAME = "__ElectronWCAPBridge__";
|
|
11
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/common/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IAClC,sBAAsB,EAAE,MAAM,CAAA;CAC9B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,qBAAqB,CAMlF;AAED,eAAO,MAAM,6BAA6B,gCAAgC,CAAC;AAE3E,eAAO,MAAM,oBAAoB,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function isCallbackInvokeRequest(msg) {
|
|
2
|
+
const mayBeRequest = msg;
|
|
3
|
+
return mayBeRequest !== null &&
|
|
4
|
+
typeof mayBeRequest.method === 'string' &&
|
|
5
|
+
Array.isArray(mayBeRequest.args);
|
|
6
|
+
}
|
|
7
|
+
const BRIDGE_INVOKE_REQUEST_CHANNEL = 'api-provider:bridge-request';
|
|
8
|
+
const CALLBACK_BRIDGE_NAME = '__ElectronWCAPBridge__';
|
|
9
|
+
|
|
10
|
+
export { BRIDGE_INVOKE_REQUEST_CHANNEL, CALLBACK_BRIDGE_NAME, isCallbackInvokeRequest };
|
|
11
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sources":["../../../../src/common/protocol.ts"],"sourcesContent":[null],"names":[],"mappings":"AASM,SAAU,uBAAuB,CAAC,GAAY,EAAA;IACnD,MAAM,YAAY,GAAG,GAA4B;IAEjD,OAAO,YAAY,KAAK,IAAI;AAC3B,QAAA,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ;AACvC,QAAA,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;AAClC;AAEO,MAAM,6BAA6B,GAAG;AAEtC,MAAM,oBAAoB,GAAG;;;;"}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC"}
|
package/esm/index.js
ADDED
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA,MAAM,cAAc,EAAE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WebContents } from 'electron';
|
|
2
|
+
export declare class CallbackRegistry {
|
|
3
|
+
private readonly callbacks;
|
|
4
|
+
constructor();
|
|
5
|
+
registerCallback(webContents: WebContents, callback: (...args: unknown[]) => unknown): string;
|
|
6
|
+
unregisterCallback(hostId: number, name: string): boolean;
|
|
7
|
+
private watchForHost;
|
|
8
|
+
}
|
|
9
|
+
export declare function globalCallbacksRegistry(): CallbackRegistry;
|
|
10
|
+
//# sourceMappingURL=callback-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-registry.d.ts","sourceRoot":"","sources":["../../../src/main/callback-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,WAAW,EAAE,MAAM,UAAU,CAAC;AAKhD,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmE;;IAoB7F,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,MAAM;IAoB7F,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAUzD,OAAO,CAAC,YAAY;CAKpB;AAID,wBAAgB,uBAAuB,IAAI,gBAAgB,CAM1D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ipcMain } from 'electron';
|
|
2
|
+
import { BRIDGE_INVOKE_REQUEST_CHANNEL, isCallbackInvokeRequest } from '../common/protocol.js';
|
|
3
|
+
import { callbackNotRegistered, nonInvocationRequest, callbackWithoutName, callbackRegisteredAlready } from '../common/errors.js';
|
|
4
|
+
|
|
5
|
+
class CallbackRegistry {
|
|
6
|
+
callbacks = new Map();
|
|
7
|
+
constructor() {
|
|
8
|
+
ipcMain.on(BRIDGE_INVOKE_REQUEST_CHANNEL, (event, msg) => {
|
|
9
|
+
if (isCallbackInvokeRequest(msg)) {
|
|
10
|
+
const callback = this.callbacks.get(event.sender.id)?.get(msg.method);
|
|
11
|
+
if (!callback) {
|
|
12
|
+
console.error(callbackNotRegistered(msg.method, event.sender.id));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
event.returnValue = callback?.(...msg.args);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.error(nonInvocationRequest());
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
registerCallback(webContents, callback) {
|
|
22
|
+
if (!callback.name) {
|
|
23
|
+
throw callbackWithoutName();
|
|
24
|
+
}
|
|
25
|
+
let callbacksByIdBucket = this.callbacks.get(webContents.id);
|
|
26
|
+
if (!callbacksByIdBucket) {
|
|
27
|
+
callbacksByIdBucket = new Map();
|
|
28
|
+
this.callbacks.set(webContents.id, callbacksByIdBucket);
|
|
29
|
+
this.watchForHost(webContents);
|
|
30
|
+
}
|
|
31
|
+
if (callbacksByIdBucket.has(callback.name)) {
|
|
32
|
+
throw callbackRegisteredAlready(callback.name, webContents.id);
|
|
33
|
+
}
|
|
34
|
+
callbacksByIdBucket.set(callback.name, callback);
|
|
35
|
+
return callback.name;
|
|
36
|
+
}
|
|
37
|
+
unregisterCallback(hostId, name) {
|
|
38
|
+
const callbacksByIdBucket = this.callbacks.get(hostId);
|
|
39
|
+
if (!callbacksByIdBucket) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return callbacksByIdBucket.delete(name);
|
|
43
|
+
}
|
|
44
|
+
watchForHost(webContents) {
|
|
45
|
+
webContents.once('destroyed', () => {
|
|
46
|
+
this.callbacks.delete(webContents.id);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
let registryInstance = null;
|
|
51
|
+
function globalCallbacksRegistry() {
|
|
52
|
+
if (!registryInstance) {
|
|
53
|
+
registryInstance = new CallbackRegistry();
|
|
54
|
+
}
|
|
55
|
+
return registryInstance;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { CallbackRegistry, globalCallbacksRegistry };
|
|
59
|
+
//# sourceMappingURL=callback-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-registry.js","sources":["../../../../src/main/callback-registry.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;MAKa,gBAAgB,CAAA;AACX,IAAA,SAAS,GAAG,IAAI,GAAG,EAAwD;AAE5F,IAAA,WAAA,GAAA;QACC,OAAO,CAAC,EAAE,CAAC,6BAA6B,EAAE,CAAC,KAA4B,EAAE,GAAY,KAAI;AACxF,YAAA,IAAI,uBAAuB,CAAC,GAAG,CAAC,EAAE;gBACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;gBAErE,IAAI,CAAC,QAAQ,EAAE;AACd,oBAAA,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACjE;gBACD;gBAEA,KAAK,CAAC,WAAW,GAAG,QAAQ,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;gBAC3C;YACD;AAEA,YAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;AACtC,QAAA,CAAC,CAAC;IACH;IAEA,gBAAgB,CAAC,WAAwB,EAAE,QAAyC,EAAA;AACnF,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;YACnB,MAAM,mBAAmB,EAAE;QAC5B;AAEA,QAAA,IAAI,mBAAmB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,mBAAmB,EAAE;AACzB,YAAA,mBAAmB,GAAG,IAAI,GAAG,EAA2C;YACxE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,mBAAmB,CAAC;AACvD,YAAA,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;QAC/B;QAEA,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YAC3C,MAAM,yBAAyB,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;QAC/D;QAEA,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;QAChD,OAAO,QAAQ,CAAC,IAAI;IACrB;IAEA,kBAAkB,CAAC,MAAc,EAAE,IAAY,EAAA;QAC9C,MAAM,mBAAmB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;QAEtD,IAAI,CAAC,mBAAmB,EAAE;AACzB,YAAA,OAAO,KAAK;QACb;AAEA,QAAA,OAAO,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;IACxC;AAEQ,IAAA,YAAY,CAAC,WAAwB,EAAA;AAC5C,QAAA,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,MAAK;YAClC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;AACtC,QAAA,CAAC,CAAC;IACH;AACA;AAED,IAAI,gBAAgB,GAA4B,IAAI;SAEpC,uBAAuB,GAAA;IACtC,IAAI,CAAC,gBAAgB,EAAE;AACtB,QAAA,gBAAgB,GAAG,IAAI,gBAAgB,EAAE;IAC1C;AAEA,IAAA,OAAO,gBAAgB;AACxB;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/main/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectable.d.ts","sourceRoot":"","sources":["../../../src/main/injectable.ts"],"names":[],"mappings":"AAGA,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CA0B/E;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { bridgeNotRegistered } from '../common/errors.js';
|
|
2
|
+
|
|
3
|
+
function invoke(apiKey, method, args) {
|
|
4
|
+
function isDispachedCallback(o) {
|
|
5
|
+
return typeof o === 'object' && typeof o.dispatchedCallbackName === 'string';
|
|
6
|
+
}
|
|
7
|
+
function checkBridgeExists() {
|
|
8
|
+
if (window.__ElectronWCAPBridge__ === null || window.__ElectronWCAPBridge__ === undefined) {
|
|
9
|
+
throw bridgeNotRegistered();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function handleDispatchedCallback(arg, index) {
|
|
13
|
+
if (isDispachedCallback(arg)) {
|
|
14
|
+
checkBridgeExists();
|
|
15
|
+
const name = arg.dispatchedCallbackName;
|
|
16
|
+
args[index] = (...cbArgs) => {
|
|
17
|
+
return window.__ElectronWCAPBridge__.invoke(name, cbArgs);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
args.map(handleDispatchedCallback);
|
|
22
|
+
const api = window[apiKey];
|
|
23
|
+
return api[method](...args);
|
|
24
|
+
}
|
|
25
|
+
function apiExists(apiKey) {
|
|
26
|
+
return window[apiKey] !== null && window[apiKey] !== undefined && typeof window[apiKey] === 'object';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { apiExists, invoke };
|
|
30
|
+
//# sourceMappingURL=injectable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectable.js","sources":["../../../../src/main/injectable.ts"],"sourcesContent":[null],"names":[],"mappings":";;SAGgB,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,IAAe,EAAA;IACrE,SAAS,mBAAmB,CAAC,CAAU,EAAA;QACtC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAQ,CAAwB,CAAC,sBAAsB,KAAK,QAAQ;IACrG;AAEA,IAAA,SAAS,iBAAiB,GAAA;AACzB,QAAA,IAAI,MAAM,CAAC,sBAAsB,KAAK,IAAI,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,EAAE;YAC1F,MAAM,mBAAmB,EAAE;QAC5B;IACD;AAEA,IAAA,SAAS,wBAAwB,CAAC,GAAY,EAAE,KAAa,EAAA;AAC5D,QAAA,IAAI,mBAAmB,CAAC,GAAG,CAAC,EAAE;AAC7B,YAAA,iBAAiB,EAAE;AAEnB,YAAA,MAAM,IAAI,GAAG,GAAG,CAAC,sBAAsB;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAiB,KAAI;gBACtC,OAAO,MAAM,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;AAC1D,YAAA,CAAC;QACF;IACD;AAEA,IAAA,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC;AAElC,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAuD;IAChF,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC;AAC5B;AAEM,SAAU,SAAS,CAAC,MAAc,EAAA;IACvC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;AACrG;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { WebContents } from 'electron';
|
|
2
|
+
import { Promisify } from 'promisify-ts';
|
|
3
|
+
export type WebContentsApiProvider<T> = Promisify<T> & {
|
|
4
|
+
readonly webContents: WebContents;
|
|
5
|
+
};
|
|
6
|
+
export declare function createApiProvider<ApiInterface>(webContents: WebContents, apiKey: string): WebContentsApiProvider<ApiInterface>;
|
|
7
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/main/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAAC;AAmE7F,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAS9H"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { globalCallbacksRegistry } from './callback-registry.js';
|
|
2
|
+
import { apiExists, invoke } from './injectable.js';
|
|
3
|
+
import { apiKeyNotExists } from '../common/errors.js';
|
|
4
|
+
|
|
5
|
+
class ApiProviderPropertiesHandler {
|
|
6
|
+
webContents;
|
|
7
|
+
apiKey;
|
|
8
|
+
callbackRegistry;
|
|
9
|
+
constructor(webContents, apiKey, callbackRegistry) {
|
|
10
|
+
this.webContents = webContents;
|
|
11
|
+
this.apiKey = apiKey;
|
|
12
|
+
this.callbackRegistry = callbackRegistry;
|
|
13
|
+
}
|
|
14
|
+
compile(fn, ...args) {
|
|
15
|
+
return `(${fn.toString()})(${this.serializeArguments(...args)})`;
|
|
16
|
+
}
|
|
17
|
+
;
|
|
18
|
+
serializeArguments(...args) {
|
|
19
|
+
const serialized = args.map((arg) => {
|
|
20
|
+
if (Array.isArray(arg)) {
|
|
21
|
+
arg.forEach((value, index) => {
|
|
22
|
+
if (typeof value === 'function') {
|
|
23
|
+
const dispatched = {
|
|
24
|
+
dispatchedCallbackName: this.callbackRegistry.registerCallback(this.webContents, value)
|
|
25
|
+
};
|
|
26
|
+
arg[index] = dispatched;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(arg);
|
|
31
|
+
});
|
|
32
|
+
return serialized.join(',');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class ApiProviderProxyHandler {
|
|
36
|
+
apiExistsAwaiter;
|
|
37
|
+
properties = {};
|
|
38
|
+
constructor(apiExistsAwaiter) {
|
|
39
|
+
this.apiExistsAwaiter = apiExistsAwaiter;
|
|
40
|
+
}
|
|
41
|
+
get(context, propertyKey) {
|
|
42
|
+
if (Object.hasOwn(context, propertyKey) || typeof context[propertyKey] === 'function') {
|
|
43
|
+
return context[propertyKey];
|
|
44
|
+
}
|
|
45
|
+
const propertyProxy = this.properties[propertyKey];
|
|
46
|
+
if (propertyProxy) {
|
|
47
|
+
return propertyProxy;
|
|
48
|
+
}
|
|
49
|
+
const apiExistsClosure = this.apiExistsAwaiter;
|
|
50
|
+
// proxy context must be a function, to allow using handler 'apply'.
|
|
51
|
+
const propProxy = new Proxy(() => { }, {
|
|
52
|
+
async apply(_target, this_, args) {
|
|
53
|
+
if (!(await apiExistsClosure)) {
|
|
54
|
+
throw apiKeyNotExists(this_.apiKey, this_.webContents.id);
|
|
55
|
+
}
|
|
56
|
+
const injectable = this_.compile(invoke, this_.apiKey, propertyKey, args);
|
|
57
|
+
return this_.webContents.executeJavaScript(injectable);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
this.properties[propertyKey] = propProxy;
|
|
61
|
+
return propProxy;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function createApiProvider(webContents, apiKey) {
|
|
65
|
+
const propertiesHandler = new ApiProviderPropertiesHandler(webContents, apiKey, globalCallbacksRegistry());
|
|
66
|
+
const checkApiExistsInjectable = propertiesHandler.compile(apiExists, apiKey);
|
|
67
|
+
const checkApiExistsPromise = webContents.executeJavaScript(checkApiExistsInjectable);
|
|
68
|
+
const proxyHandler = new ApiProviderProxyHandler(checkApiExistsPromise);
|
|
69
|
+
return new Proxy(propertiesHandler, proxyHandler);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { createApiProvider };
|
|
73
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sources":["../../../../src/main/provider.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/esm/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../../src/preload/bridge.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,IAAI,IAAI,CAWtC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
2
|
+
import { CALLBACK_BRIDGE_NAME, BRIDGE_INVOKE_REQUEST_CHANNEL } from '../common/protocol.js';
|
|
3
|
+
|
|
4
|
+
function enableCallbacks() {
|
|
5
|
+
contextBridge.exposeInMainWorld(CALLBACK_BRIDGE_NAME, {
|
|
6
|
+
invoke(callbackName, args) {
|
|
7
|
+
const invokeRequest = {
|
|
8
|
+
method: callbackName,
|
|
9
|
+
args
|
|
10
|
+
};
|
|
11
|
+
return ipcRenderer.sendSync(BRIDGE_INVOKE_REQUEST_CHANNEL, invokeRequest);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { enableCallbacks };
|
|
17
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sources":["../../../../src/preload/bridge.ts"],"sourcesContent":[null],"names":[],"mappings":";;;SAIgB,eAAe,GAAA;AAC9B,IAAA,aAAa,CAAC,iBAAiB,CAAC,oBAAoB,EAAE;QACrD,MAAM,CAAC,YAAoB,EAAE,IAAe,EAAA;AAC3C,YAAA,MAAM,aAAa,GAA0B;AAC5C,gBAAA,MAAM,EAAE,YAAY;gBACpB;aACA;YAED,OAAO,WAAW,CAAC,QAAQ,CAAC,6BAA6B,EAAE,aAAa,CAAC;QAC1E;AACA,KAAA,CAAC;AACH;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/preload/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/index.d.ts
ADDED
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC"}
|
package/index.js
ADDED
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":["exportFromRoot"],"mappings":";;AAEA,MAAMA,qBAAc,EAAE;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WebContents } from 'electron';
|
|
2
|
+
export declare class CallbackRegistry {
|
|
3
|
+
private readonly callbacks;
|
|
4
|
+
constructor();
|
|
5
|
+
registerCallback(webContents: WebContents, callback: (...args: unknown[]) => unknown): string;
|
|
6
|
+
unregisterCallback(hostId: number, name: string): boolean;
|
|
7
|
+
private watchForHost;
|
|
8
|
+
}
|
|
9
|
+
export declare function globalCallbacksRegistry(): CallbackRegistry;
|
|
10
|
+
//# sourceMappingURL=callback-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-registry.d.ts","sourceRoot":"","sources":["../../src/main/callback-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,WAAW,EAAE,MAAM,UAAU,CAAC;AAKhD,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmE;;IAoB7F,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,MAAM;IAoB7F,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAUzD,OAAO,CAAC,YAAY;CAKpB;AAID,wBAAgB,uBAAuB,IAAI,gBAAgB,CAM1D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const electron = require('electron');
|
|
2
|
+
const protocol = require('../common/protocol.js');
|
|
3
|
+
const errors = require('../common/errors.js');
|
|
4
|
+
|
|
5
|
+
class CallbackRegistry {
|
|
6
|
+
callbacks = new Map();
|
|
7
|
+
constructor() {
|
|
8
|
+
electron.ipcMain.on(protocol.BRIDGE_INVOKE_REQUEST_CHANNEL, (event, msg) => {
|
|
9
|
+
if (protocol.isCallbackInvokeRequest(msg)) {
|
|
10
|
+
const callback = this.callbacks.get(event.sender.id)?.get(msg.method);
|
|
11
|
+
if (!callback) {
|
|
12
|
+
console.error(errors.callbackNotRegistered(msg.method, event.sender.id));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
event.returnValue = callback?.(...msg.args);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.error(errors.nonInvocationRequest());
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
registerCallback(webContents, callback) {
|
|
22
|
+
if (!callback.name) {
|
|
23
|
+
throw errors.callbackWithoutName();
|
|
24
|
+
}
|
|
25
|
+
let callbacksByIdBucket = this.callbacks.get(webContents.id);
|
|
26
|
+
if (!callbacksByIdBucket) {
|
|
27
|
+
callbacksByIdBucket = new Map();
|
|
28
|
+
this.callbacks.set(webContents.id, callbacksByIdBucket);
|
|
29
|
+
this.watchForHost(webContents);
|
|
30
|
+
}
|
|
31
|
+
if (callbacksByIdBucket.has(callback.name)) {
|
|
32
|
+
throw errors.callbackRegisteredAlready(callback.name, webContents.id);
|
|
33
|
+
}
|
|
34
|
+
callbacksByIdBucket.set(callback.name, callback);
|
|
35
|
+
return callback.name;
|
|
36
|
+
}
|
|
37
|
+
unregisterCallback(hostId, name) {
|
|
38
|
+
const callbacksByIdBucket = this.callbacks.get(hostId);
|
|
39
|
+
if (!callbacksByIdBucket) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return callbacksByIdBucket.delete(name);
|
|
43
|
+
}
|
|
44
|
+
watchForHost(webContents) {
|
|
45
|
+
webContents.once('destroyed', () => {
|
|
46
|
+
this.callbacks.delete(webContents.id);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
let registryInstance = null;
|
|
51
|
+
function globalCallbacksRegistry() {
|
|
52
|
+
if (!registryInstance) {
|
|
53
|
+
registryInstance = new CallbackRegistry();
|
|
54
|
+
}
|
|
55
|
+
return registryInstance;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.CallbackRegistry = CallbackRegistry;
|
|
59
|
+
exports.globalCallbacksRegistry = globalCallbacksRegistry;
|
|
60
|
+
//# sourceMappingURL=callback-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback-registry.js","sources":["../../src/main/callback-registry.ts"],"sourcesContent":[null],"names":["ipcMain","BRIDGE_INVOKE_REQUEST_CHANNEL","isCallbackInvokeRequest","callbackNotRegistered","nonInvocationRequest","callbackWithoutName","callbackRegisteredAlready"],"mappings":";;;;MAKa,gBAAgB,CAAA;AACX,IAAA,SAAS,GAAG,IAAI,GAAG,EAAwD;AAE5F,IAAA,WAAA,GAAA;QACCA,gBAAO,CAAC,EAAE,CAACC,sCAA6B,EAAE,CAAC,KAA4B,EAAE,GAAY,KAAI;AACxF,YAAA,IAAIC,gCAAuB,CAAC,GAAG,CAAC,EAAE;gBACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;gBAErE,IAAI,CAAC,QAAQ,EAAE;AACd,oBAAA,OAAO,CAAC,KAAK,CAACC,4BAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBACjE;gBACD;gBAEA,KAAK,CAAC,WAAW,GAAG,QAAQ,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;gBAC3C;YACD;AAEA,YAAA,OAAO,CAAC,KAAK,CAACC,2BAAoB,EAAE,CAAC;AACtC,QAAA,CAAC,CAAC;IACH;IAEA,gBAAgB,CAAC,WAAwB,EAAE,QAAyC,EAAA;AACnF,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;YACnB,MAAMC,0BAAmB,EAAE;QAC5B;AAEA,QAAA,IAAI,mBAAmB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,mBAAmB,EAAE;AACzB,YAAA,mBAAmB,GAAG,IAAI,GAAG,EAA2C;YACxE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,mBAAmB,CAAC;AACvD,YAAA,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC;QAC/B;QAEA,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YAC3C,MAAMC,gCAAyB,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;QAC/D;QAEA,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;QAChD,OAAO,QAAQ,CAAC,IAAI;IACrB;IAEA,kBAAkB,CAAC,MAAc,EAAE,IAAY,EAAA;QAC9C,MAAM,mBAAmB,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;QAEtD,IAAI,CAAC,mBAAmB,EAAE;AACzB,YAAA,OAAO,KAAK;QACb;AAEA,QAAA,OAAO,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;IACxC;AAEQ,IAAA,YAAY,CAAC,WAAwB,EAAA;AAC5C,QAAA,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,MAAK;YAClC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;AACtC,QAAA,CAAC,CAAC;IACH;AACA;AAED,IAAI,gBAAgB,GAA4B,IAAI;SAEpC,uBAAuB,GAAA;IACtC,IAAI,CAAC,gBAAgB,EAAE;AACtB,QAAA,gBAAgB,GAAG,IAAI,gBAAgB,EAAE;IAC1C;AAEA,IAAA,OAAO,gBAAgB;AACxB;;;;;"}
|
package/main/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/main/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
package/main/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectable.d.ts","sourceRoot":"","sources":["../../src/main/injectable.ts"],"names":[],"mappings":"AAGA,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CA0B/E;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const errors = require('../common/errors.js');
|
|
2
|
+
|
|
3
|
+
function invoke(apiKey, method, args) {
|
|
4
|
+
function isDispachedCallback(o) {
|
|
5
|
+
return typeof o === 'object' && typeof o.dispatchedCallbackName === 'string';
|
|
6
|
+
}
|
|
7
|
+
function checkBridgeExists() {
|
|
8
|
+
if (window.__ElectronWCAPBridge__ === null || window.__ElectronWCAPBridge__ === undefined) {
|
|
9
|
+
throw errors.bridgeNotRegistered();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function handleDispatchedCallback(arg, index) {
|
|
13
|
+
if (isDispachedCallback(arg)) {
|
|
14
|
+
checkBridgeExists();
|
|
15
|
+
const name = arg.dispatchedCallbackName;
|
|
16
|
+
args[index] = (...cbArgs) => {
|
|
17
|
+
return window.__ElectronWCAPBridge__.invoke(name, cbArgs);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
args.map(handleDispatchedCallback);
|
|
22
|
+
const api = window[apiKey];
|
|
23
|
+
return api[method](...args);
|
|
24
|
+
}
|
|
25
|
+
function apiExists(apiKey) {
|
|
26
|
+
return window[apiKey] !== null && window[apiKey] !== undefined && typeof window[apiKey] === 'object';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.apiExists = apiExists;
|
|
30
|
+
exports.invoke = invoke;
|
|
31
|
+
//# sourceMappingURL=injectable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injectable.js","sources":["../../src/main/injectable.ts"],"sourcesContent":[null],"names":["bridgeNotRegistered"],"mappings":";;SAGgB,MAAM,CAAC,MAAc,EAAE,MAAc,EAAE,IAAe,EAAA;IACrE,SAAS,mBAAmB,CAAC,CAAU,EAAA;QACtC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAQ,CAAwB,CAAC,sBAAsB,KAAK,QAAQ;IACrG;AAEA,IAAA,SAAS,iBAAiB,GAAA;AACzB,QAAA,IAAI,MAAM,CAAC,sBAAsB,KAAK,IAAI,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,EAAE;YAC1F,MAAMA,0BAAmB,EAAE;QAC5B;IACD;AAEA,IAAA,SAAS,wBAAwB,CAAC,GAAY,EAAE,KAAa,EAAA;AAC5D,QAAA,IAAI,mBAAmB,CAAC,GAAG,CAAC,EAAE;AAC7B,YAAA,iBAAiB,EAAE;AAEnB,YAAA,MAAM,IAAI,GAAG,GAAG,CAAC,sBAAsB;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAiB,KAAI;gBACtC,OAAO,MAAM,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;AAC1D,YAAA,CAAC;QACF;IACD;AAEA,IAAA,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC;AAElC,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAuD;IAChF,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC;AAC5B;AAEM,SAAU,SAAS,CAAC,MAAc,EAAA;IACvC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;AACrG;;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { WebContents } from 'electron';
|
|
2
|
+
import { Promisify } from 'promisify-ts';
|
|
3
|
+
export type WebContentsApiProvider<T> = Promisify<T> & {
|
|
4
|
+
readonly webContents: WebContents;
|
|
5
|
+
};
|
|
6
|
+
export declare function createApiProvider<ApiInterface>(webContents: WebContents, apiKey: string): WebContentsApiProvider<ApiInterface>;
|
|
7
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/main/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAAC;AAmE7F,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAS9H"}
|
package/main/provider.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const callbackRegistry = require('./callback-registry.js');
|
|
2
|
+
const injectable = require('./injectable.js');
|
|
3
|
+
const errors = require('../common/errors.js');
|
|
4
|
+
|
|
5
|
+
class ApiProviderPropertiesHandler {
|
|
6
|
+
webContents;
|
|
7
|
+
apiKey;
|
|
8
|
+
callbackRegistry;
|
|
9
|
+
constructor(webContents, apiKey, callbackRegistry) {
|
|
10
|
+
this.webContents = webContents;
|
|
11
|
+
this.apiKey = apiKey;
|
|
12
|
+
this.callbackRegistry = callbackRegistry;
|
|
13
|
+
}
|
|
14
|
+
compile(fn, ...args) {
|
|
15
|
+
return `(${fn.toString()})(${this.serializeArguments(...args)})`;
|
|
16
|
+
}
|
|
17
|
+
;
|
|
18
|
+
serializeArguments(...args) {
|
|
19
|
+
const serialized = args.map((arg) => {
|
|
20
|
+
if (Array.isArray(arg)) {
|
|
21
|
+
arg.forEach((value, index) => {
|
|
22
|
+
if (typeof value === 'function') {
|
|
23
|
+
const dispatched = {
|
|
24
|
+
dispatchedCallbackName: this.callbackRegistry.registerCallback(this.webContents, value)
|
|
25
|
+
};
|
|
26
|
+
arg[index] = dispatched;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(arg);
|
|
31
|
+
});
|
|
32
|
+
return serialized.join(',');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class ApiProviderProxyHandler {
|
|
36
|
+
apiExistsAwaiter;
|
|
37
|
+
properties = {};
|
|
38
|
+
constructor(apiExistsAwaiter) {
|
|
39
|
+
this.apiExistsAwaiter = apiExistsAwaiter;
|
|
40
|
+
}
|
|
41
|
+
get(context, propertyKey) {
|
|
42
|
+
if (Object.hasOwn(context, propertyKey) || typeof context[propertyKey] === 'function') {
|
|
43
|
+
return context[propertyKey];
|
|
44
|
+
}
|
|
45
|
+
const propertyProxy = this.properties[propertyKey];
|
|
46
|
+
if (propertyProxy) {
|
|
47
|
+
return propertyProxy;
|
|
48
|
+
}
|
|
49
|
+
const apiExistsClosure = this.apiExistsAwaiter;
|
|
50
|
+
// proxy context must be a function, to allow using handler 'apply'.
|
|
51
|
+
const propProxy = new Proxy(() => { }, {
|
|
52
|
+
async apply(_target, this_, args) {
|
|
53
|
+
if (!(await apiExistsClosure)) {
|
|
54
|
+
throw errors.apiKeyNotExists(this_.apiKey, this_.webContents.id);
|
|
55
|
+
}
|
|
56
|
+
const injectable$1 = this_.compile(injectable.invoke, this_.apiKey, propertyKey, args);
|
|
57
|
+
return this_.webContents.executeJavaScript(injectable$1);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
this.properties[propertyKey] = propProxy;
|
|
61
|
+
return propProxy;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function createApiProvider(webContents, apiKey) {
|
|
65
|
+
const propertiesHandler = new ApiProviderPropertiesHandler(webContents, apiKey, callbackRegistry.globalCallbacksRegistry());
|
|
66
|
+
const checkApiExistsInjectable = propertiesHandler.compile(injectable.apiExists, apiKey);
|
|
67
|
+
const checkApiExistsPromise = webContents.executeJavaScript(checkApiExistsInjectable);
|
|
68
|
+
const proxyHandler = new ApiProviderProxyHandler(checkApiExistsPromise);
|
|
69
|
+
return new Proxy(propertiesHandler, proxyHandler);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.createApiProvider = createApiProvider;
|
|
73
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sources":["../../src/main/provider.ts"],"sourcesContent":[null],"names":["apiKeyNotExists","injectable","invoke","globalCallbacksRegistry","apiExists"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "electron-wcap",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "Egor Kushnarev",
|
|
5
|
+
"description": "Electron WebContent API Provider — call renderer APIs from the main process with support for passing callbacks.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"electron",
|
|
9
|
+
"webcontent",
|
|
10
|
+
"executeJavaScript",
|
|
11
|
+
"renderer",
|
|
12
|
+
"API"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/origin-yaropolk/electron-wcap",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/origin-yaropolk/electron-wcap"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
"./main": {
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./main/index.d.ts",
|
|
23
|
+
"default": "./main/index.js"
|
|
24
|
+
},
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./esm/main/index.d.ts",
|
|
27
|
+
"default": "./esm/main/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./preload": {
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./preload/index.d.ts",
|
|
33
|
+
"default": "./preload/index.js"
|
|
34
|
+
},
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./esm/preload/index.d.ts",
|
|
37
|
+
"default": "./esm/preload/index.js"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"module": "./esm/main/index.js",
|
|
42
|
+
"browser": "./esm/renderer/index.js"
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/preload/bridge.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,IAAI,IAAI,CAWtC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const electron = require('electron');
|
|
2
|
+
const protocol = require('../common/protocol.js');
|
|
3
|
+
|
|
4
|
+
function enableCallbacks() {
|
|
5
|
+
electron.contextBridge.exposeInMainWorld(protocol.CALLBACK_BRIDGE_NAME, {
|
|
6
|
+
invoke(callbackName, args) {
|
|
7
|
+
const invokeRequest = {
|
|
8
|
+
method: callbackName,
|
|
9
|
+
args
|
|
10
|
+
};
|
|
11
|
+
return electron.ipcRenderer.sendSync(protocol.BRIDGE_INVOKE_REQUEST_CHANNEL, invokeRequest);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.enableCallbacks = enableCallbacks;
|
|
17
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sources":["../../src/preload/bridge.ts"],"sourcesContent":[null],"names":["contextBridge","CALLBACK_BRIDGE_NAME","ipcRenderer","BRIDGE_INVOKE_REQUEST_CHANNEL"],"mappings":";;;SAIgB,eAAe,GAAA;AAC9B,IAAAA,sBAAa,CAAC,iBAAiB,CAACC,6BAAoB,EAAE;QACrD,MAAM,CAAC,YAAoB,EAAE,IAAe,EAAA;AAC3C,YAAA,MAAM,aAAa,GAA0B;AAC5C,gBAAA,MAAM,EAAE,YAAY;gBACpB;aACA;YAED,OAAOC,oBAAW,CAAC,QAAQ,CAACC,sCAA6B,EAAE,aAAa,CAAC;QAC1E;AACA,KAAA,CAAC;AACH;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/preload/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
|
package/preload/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|