@canlooks/roost-electron 0.0.1
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 +224 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +10 -0
- package/dist/cjs/registerIpcMain.d.ts +3 -0
- package/dist/cjs/registerIpcMain.js +10 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/registerIpcMain.d.ts +3 -0
- package/dist/esm/registerIpcMain.js +7 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 C.CanLiang
|
|
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,224 @@
|
|
|
1
|
+
# @canlooks/roost-electron
|
|
2
|
+
|
|
3
|
+
Electron main process plugin for the [Roost](https://github.com/canlooks/roost) microservice framework. Bridges Electron's IPC (Inter-Process Communication) from renderer processes directly to Roost service controllers running in the main process.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@canlooks/roost-electron` is a lightweight plugin that registers an [`ipcMain.handle()`](https://www.electronjs.org/docs/latest/api/ipc-main#ipcmainhandlechannel-listener) listener on a configurable channel. When a renderer process sends an IPC invoke call, the plugin forwards the invocation key and arguments to `app.invoke()`, routing the request to the matching Roost controller action.
|
|
8
|
+
|
|
9
|
+
Paired with [`@canlooks/roost-electron-renderer`](https://www.npmjs.com/package/@canlooks/roost-electron-renderer) on the renderer side, this enables seamless RPC-style communication where renderer-side controller method calls are transparently proxied via Electron IPC to the main process.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @canlooks/roost-electron
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Peer dependencies:**
|
|
18
|
+
- `@canlooks/roost` (core framework)
|
|
19
|
+
- `electron` (main process runtime)
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Main Process
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { app, BrowserWindow } from 'electron'
|
|
27
|
+
import Roost from '@canlooks/roost'
|
|
28
|
+
import { ElectronMainPlugin } from '@canlooks/roost-electron'
|
|
29
|
+
import { MyService } from './services/MyService'
|
|
30
|
+
|
|
31
|
+
async function main() {
|
|
32
|
+
const roost = await Roost.create({
|
|
33
|
+
named: { MyService },
|
|
34
|
+
plugins: [
|
|
35
|
+
ElectronMainPlugin()
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const win = new BrowserWindow({
|
|
40
|
+
webPreferences: {
|
|
41
|
+
preload: path.join(__dirname, 'preload.js')
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
win.loadFile('index.html')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
app.whenReady().then(main)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Renderer Process (with `@canlooks/roost-electron-renderer`)
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { contextBridge, ipcRenderer } from 'electron'
|
|
54
|
+
import { createRoostRenderer } from '@canlooks/roost-electron-renderer'
|
|
55
|
+
import { MyService } from '../services/MyService'
|
|
56
|
+
|
|
57
|
+
contextBridge.exposeInMainWorld('roost', {
|
|
58
|
+
services: await createRoostRenderer(
|
|
59
|
+
{ MyService },
|
|
60
|
+
{ ipcRenderer }
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then, in the renderer page:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// MyService methods are transparently proxied to the main process
|
|
69
|
+
const result = await window.roost.services.MyService.doSomething(args)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API Reference
|
|
73
|
+
|
|
74
|
+
### `ElectronMainPlugin(options?)`
|
|
75
|
+
|
|
76
|
+
Factory function that creates a Roost `Plugin` object for the Electron main process.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
function ElectronMainPlugin(options?: ElectronMainPluginOptions): Plugin
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### `ElectronMainPluginOptions`
|
|
83
|
+
|
|
84
|
+
| Property | Type | Default | Description |
|
|
85
|
+
| --------- | -------- | ----------------------------- | ---------------------------------------------------------- |
|
|
86
|
+
| `channel` | `string` | `"@canlooks/roost-electron"` | The IPC channel name used for `ipcMain.handle()`. Customize this to avoid conflicts with other IPC handlers. |
|
|
87
|
+
|
|
88
|
+
#### Return Value
|
|
89
|
+
|
|
90
|
+
Returns a `Plugin` object conforming to the Roost `Plugin` interface:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{
|
|
94
|
+
name: 'electron-main',
|
|
95
|
+
onStaticInjected: (app: Roost) => void
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `registerIpcMain(app, options?)`
|
|
100
|
+
|
|
101
|
+
Low-level function called internally by the plugin. Registers the `ipcMain.handle()` listener directly.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
function registerIpcMain(app: Roost, options?: ElectronMainPluginOptions): void
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> This is exported for advanced use cases where you need to control registration timing manually. In most cases, use `ElectronMainPlugin()` instead.
|
|
108
|
+
|
|
109
|
+
## How It Works
|
|
110
|
+
|
|
111
|
+
### Architecture
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
┌─────────────────────────────────────────────────────────┐
|
|
115
|
+
│ Renderer Process │
|
|
116
|
+
│ ┌───────────────────────────────────────────────────┐ │
|
|
117
|
+
│ │ createRoostRenderer({ MyService }, { ipcRenderer })│ │
|
|
118
|
+
│ │ → Rewrites MyService methods to call │ │
|
|
119
|
+
│ │ ipcRenderer.invoke(channel, key, ...args) │ │
|
|
120
|
+
│ └───────────────────────┬───────────────────────────┘ │
|
|
121
|
+
└──────────────────────────┼──────────────────────────────┘
|
|
122
|
+
│ Electron IPC
|
|
123
|
+
┌──────────────────────────┼──────────────────────────────┐
|
|
124
|
+
│ Main Process │ │
|
|
125
|
+
│ ┌───────────────────────▼───────────────────────────┐ │
|
|
126
|
+
│ │ ElectronMainPlugin │ │
|
|
127
|
+
│ │ → ipcMain.handle(channel, (e, key, ...args) => { │ │
|
|
128
|
+
│ │ return app.invoke(key, ...args) │ │
|
|
129
|
+
│ │ }) │ │
|
|
130
|
+
│ └───────────────────────┬───────────────────────────┘ │
|
|
131
|
+
│ │ │
|
|
132
|
+
│ ┌───────────────────────▼───────────────────────────┐ │
|
|
133
|
+
│ │ Roost App │ │
|
|
134
|
+
│ │ → app.invoke(key, ...args) │ │
|
|
135
|
+
│ │ → Route to matching @Controller/@Action │ │
|
|
136
|
+
│ │ → Execute, return result │ │
|
|
137
|
+
│ └───────────────────────────────────────────────────┘ │
|
|
138
|
+
└─────────────────────────────────────────────────────────┘
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Lifecycle
|
|
142
|
+
|
|
143
|
+
The plugin hooks into the `onStaticInjected` lifecycle event of Roost:
|
|
144
|
+
|
|
145
|
+
1. **`Roost.create()`** is called with the plugin in the `plugins` array.
|
|
146
|
+
2. Roost registers all modules and performs dependency injection.
|
|
147
|
+
3. **`onStaticInjected`** fires — the plugin registers `ipcMain.handle()` on the configured channel.
|
|
148
|
+
4. The main process is now ready to receive IPC calls from renderer processes.
|
|
149
|
+
|
|
150
|
+
### Invocation Flow
|
|
151
|
+
|
|
152
|
+
When a renderer calls `window.roost.services.MyService.doSomething(arg)`:
|
|
153
|
+
|
|
154
|
+
1. `@canlooks/roost-electron-renderer` rewrites the method to call `ipcRenderer.invoke('@canlooks/roost-electron', 'path/to/action', arg)`.
|
|
155
|
+
2. The IPC message arrives in the main process.
|
|
156
|
+
3. The `ipcMain.handle()` listener receives `(event, key, arg)`.
|
|
157
|
+
4. It calls `app.invoke(key, arg)` on the Roost instance.
|
|
158
|
+
5. Roost's `Invoker` matches the key against registered controllers and actions (path-based, pattern-based, or regex-based routing).
|
|
159
|
+
6. The matched controller method executes and returns a result.
|
|
160
|
+
7. The result is sent back through the IPC channel to the renderer.
|
|
161
|
+
|
|
162
|
+
## Custom Channel
|
|
163
|
+
|
|
164
|
+
If the default channel name conflicts with other IPC handlers in your application, provide a custom channel:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
ElectronMainPlugin({ channel: 'my-app:rpc' })
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Make sure to use the same channel name in the renderer side:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
createRoostRenderer(
|
|
174
|
+
{ MyService },
|
|
175
|
+
{ ipcRenderer, channel: 'my-app:rpc' }
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Project Structure
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
packages/electron/
|
|
183
|
+
├── src/
|
|
184
|
+
│ ├── index.ts # Plugin factory + type exports
|
|
185
|
+
│ └── registerIpcMain.ts # IPC handler registration
|
|
186
|
+
├── dist/
|
|
187
|
+
│ ├── cjs/ # CommonJS build output
|
|
188
|
+
│ └── esm/ # ES Module build output
|
|
189
|
+
├── test/
|
|
190
|
+
├── package.json
|
|
191
|
+
├── tsconfig.json
|
|
192
|
+
├── LICENSE
|
|
193
|
+
└── README.md
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## TypeScript
|
|
197
|
+
|
|
198
|
+
The package is written in TypeScript and ships with declaration files. TypeScript 6.0+ and `strict` mode are used during development.
|
|
199
|
+
|
|
200
|
+
### Exports
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Factory function
|
|
204
|
+
export function ElectronMainPlugin(options?: ElectronMainPluginOptions): Plugin
|
|
205
|
+
|
|
206
|
+
// Options type
|
|
207
|
+
export type ElectronMainPluginOptions = {
|
|
208
|
+
channel?: string
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Low-level registration function
|
|
212
|
+
export function registerIpcMain(app: Roost, options?: ElectronMainPluginOptions): void
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Related Packages
|
|
216
|
+
|
|
217
|
+
| Package | Description |
|
|
218
|
+
| ------- | ----------- |
|
|
219
|
+
| [`@canlooks/roost`](https://www.npmjs.com/package/@canlooks/roost) | Core microservice framework |
|
|
220
|
+
| [`@canlooks/roost-electron-renderer`](https://www.npmjs.com/package/@canlooks/roost-electron-renderer) | Renderer-side companion — creates proxy controllers that communicate via IPC |
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT © [C.CanLiang](https://github.com/canlooks)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ElectronMainPlugin = ElectronMainPlugin;
|
|
4
|
+
const registerIpcMain_1 = require("./registerIpcMain");
|
|
5
|
+
function ElectronMainPlugin(options) {
|
|
6
|
+
return {
|
|
7
|
+
name: 'electron-main',
|
|
8
|
+
onStaticInjected: app => (0, registerIpcMain_1.registerIpcMain)(app, options)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerIpcMain = registerIpcMain;
|
|
4
|
+
const electron_1 = require("electron");
|
|
5
|
+
function registerIpcMain(app, options) {
|
|
6
|
+
const channel = options?.channel || '@canlooks/roost-electron';
|
|
7
|
+
electron_1.ipcMain.handle(channel, (e, key, ...args) => {
|
|
8
|
+
return app.invoke(key, ...args);
|
|
9
|
+
});
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@canlooks/roost-electron",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"author": "C.CanLiang <canlooks@gmail.com>",
|
|
5
|
+
"description": "A backend micro service framework",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"micro service"
|
|
8
|
+
],
|
|
9
|
+
"main": "dist/cjs/index.js",
|
|
10
|
+
"module": "dist/esm/index.js",
|
|
11
|
+
"types": "dist/esm/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/esm/index.d.ts",
|
|
15
|
+
"import": "./dist/esm/index.js",
|
|
16
|
+
"require": "./dist/cjs/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"registry": "https://registry.npmjs.org/"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/canlooks/roost"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/canlooks/roost",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/canlooks/roost/issues",
|
|
30
|
+
"email": "canlooks@gmail.com"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"clean": "npx shx rm -rf dist",
|
|
35
|
+
"build": "tsc -m esnext --outDir dist/esm & tsc -m commonjs --outDir dist/cjs",
|
|
36
|
+
"build:alias": "tsc-alias --outDir dist/esm",
|
|
37
|
+
"rebuild": "npm run clean && npm run build && npm run build:alias"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@canlooks/roost": "^0.0.1",
|
|
41
|
+
"tslib": "^2.8.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/express": "^5.0.6",
|
|
45
|
+
"@types/node": "^25.9.1",
|
|
46
|
+
"electron": "^42.3.0",
|
|
47
|
+
"tsc-alias": "^1.8.17",
|
|
48
|
+
"typescript": "^6.0.3"
|
|
49
|
+
}
|
|
50
|
+
}
|