@canlooks/roost-electron-renderer 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 +275 -0
- package/dist/cjs/createRenderer.d.ts +7 -0
- package/dist/cjs/createRenderer.js +17 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/rewriteAction.d.ts +2 -0
- package/dist/cjs/rewriteAction.js +19 -0
- package/dist/esm/createRenderer.d.ts +7 -0
- package/dist/esm/createRenderer.js +14 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/rewriteAction.d.ts +2 -0
- package/dist/esm/rewriteAction.js +16 -0
- package/package.json +57 -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,275 @@
|
|
|
1
|
+
# @canlooks/roost-electron-renderer
|
|
2
|
+
|
|
3
|
+
Electron renderer process plugin for the [Roost](https://github.com/canlooks/roost) micro-service framework. Provides seamless IPC-based remote procedure call (RPC) proxying — call main-process controller actions from the renderer as if they were local methods.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
In an Electron application, business logic typically runs in the main process via Roost controllers decorated with `@Controller` and `@Action`. This package creates transparent **proxy instances** of those controllers in the renderer process. Every `@Action`-decorated method on a proxy is replaced with an `ipcRenderer.invoke()` call, routing arguments through Electron's IPC channel to the main process and returning the result as a promise.
|
|
8
|
+
|
|
9
|
+
The renderer code never touches IPC directly — it simply calls methods on controller instances.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─ Renderer Process ─────────────────────┐
|
|
13
|
+
│ │
|
|
14
|
+
│ const { myCtrl } = │
|
|
15
|
+
│ await createRoostRenderer( │
|
|
16
|
+
│ { MyController }, │
|
|
17
|
+
│ { ipcRenderer } │
|
|
18
|
+
│ ) │
|
|
19
|
+
│ │
|
|
20
|
+
│ // Looks like a local call... │
|
|
21
|
+
│ const result = await myCtrl.doWork(x) │
|
|
22
|
+
│ │ │
|
|
23
|
+
└─────────────────────┼───────────────────┘
|
|
24
|
+
│ ipcRenderer.invoke(channel, path, ...args)
|
|
25
|
+
▼
|
|
26
|
+
┌─ Main Process ─────────────────────────┐
|
|
27
|
+
│ │
|
|
28
|
+
│ @Controller('api') │
|
|
29
|
+
│ class MyController { │
|
|
30
|
+
│ @Action('doWork') │
|
|
31
|
+
│ doWork(x) { ... } │
|
|
32
|
+
│ } │
|
|
33
|
+
│ │
|
|
34
|
+
└─────────────────────────────────────────┘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @canlooks/roost-electron-renderer
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Peer dependencies:**
|
|
44
|
+
|
|
45
|
+
- [`@canlooks/roost`](https://www.npmjs.com/package/@canlooks/roost) — the core Roost framework
|
|
46
|
+
- [`electron`](https://www.npmjs.com/package/electron) — provides `ipcRenderer`
|
|
47
|
+
|
|
48
|
+
## API Reference
|
|
49
|
+
|
|
50
|
+
### `createRoostRenderer(controllers, options)`
|
|
51
|
+
|
|
52
|
+
Creates proxy controller instances whose `@Action` methods are wired to `ipcRenderer.invoke`.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
function createRoostRenderer<T extends Record<string, ComponentType>>(
|
|
56
|
+
controllers: T,
|
|
57
|
+
options: CreateRoostRendererOptions
|
|
58
|
+
): Promise<{ [K in keyof T]: InstanceType<T[K]> }>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Parameters
|
|
62
|
+
|
|
63
|
+
| Parameter | Type | Description |
|
|
64
|
+
|-----------|------|-------------|
|
|
65
|
+
| `controllers` | `Record<string, ComponentType>` | Map of controller classes keyed by name. Each class must be decorated with `@Controller` from `@canlooks/roost`. |
|
|
66
|
+
| `options` | `CreateRoostRendererOptions` | Configuration for the renderer proxy. |
|
|
67
|
+
|
|
68
|
+
#### Returns
|
|
69
|
+
|
|
70
|
+
An object with the same keys as the input `controllers` map, where each value is an **instance** of the corresponding controller class with its `@Action` methods rewritten to invoke IPC.
|
|
71
|
+
|
|
72
|
+
#### `CreateRoostRendererOptions`
|
|
73
|
+
|
|
74
|
+
| Property | Type | Required | Default | Description |
|
|
75
|
+
|----------|------|----------|---------|-------------|
|
|
76
|
+
| `ipcRenderer` | `IpcRenderer` | Yes | — | The Electron `ipcRenderer` instance from the renderer process. |
|
|
77
|
+
| `channel` | `string` | No | `'@canlooks/roost-electron'` | Custom IPC channel name. |
|
|
78
|
+
|
|
79
|
+
### `rewriteActions(instances, options)`
|
|
80
|
+
|
|
81
|
+
> **Internal.** Exported for advanced use cases. Rewrites `@Action` methods on controller instances to proxy through `ipcRenderer.invoke`.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
function rewriteActions(
|
|
85
|
+
instances: any[],
|
|
86
|
+
options: CreateRoostRendererOptions
|
|
87
|
+
): void
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## How It Works
|
|
91
|
+
|
|
92
|
+
### Action Path Resolution
|
|
93
|
+
|
|
94
|
+
Each `@Action`-decorated method is mapped to an IPC key derived from the controller and action paths:
|
|
95
|
+
|
|
96
|
+
| Controller Decorator | Action Decorator | Resolved IPC Key |
|
|
97
|
+
|----------------------|------------------|------------------|
|
|
98
|
+
| `@Controller('api')` | `@Action('hello')` | `'/api/hello'` |
|
|
99
|
+
| `@Controller('users')` | `@Action('list')` | `'/users/list'` |
|
|
100
|
+
| `@Controller()` | `@Action('status')` | `'/status'` |
|
|
101
|
+
|
|
102
|
+
The resolved key is passed as the second argument to `ipcRenderer.invoke(channel, key, ...args)`.
|
|
103
|
+
|
|
104
|
+
### Method Rewriting
|
|
105
|
+
|
|
106
|
+
- Only methods decorated with `@Action` are rewritten. Regular methods and properties are left untouched.
|
|
107
|
+
- Rewriting happens **per-instance**, not on the prototype. The original class prototype remains intact.
|
|
108
|
+
- Each call to a rewritten method results in a fresh `ipcRenderer.invoke()` call — no caching or batching.
|
|
109
|
+
- All arguments passed to the method are forwarded as variadic arguments to `ipcRenderer.invoke`.
|
|
110
|
+
- The return value of `ipcRenderer.invoke` (a `Promise`) is returned directly, preserving the original reference.
|
|
111
|
+
|
|
112
|
+
### Error Propagation
|
|
113
|
+
|
|
114
|
+
Errors thrown by the main process handler (or IPC errors) are propagated as rejected promises:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const { ctrl } = await createRoostRenderer({ TestController }, { ipcRenderer })
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await ctrl.hello('World')
|
|
121
|
+
} catch (err) {
|
|
122
|
+
// err is the exact rejection from ipcRenderer.invoke
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Usage
|
|
127
|
+
|
|
128
|
+
### Basic Example
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
132
|
+
// Shared controller definition (e.g., in a shared package)
|
|
133
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
134
|
+
|
|
135
|
+
import { Controller, Action } from '@canlooks/roost'
|
|
136
|
+
|
|
137
|
+
@Controller('api')
|
|
138
|
+
export class ApiController {
|
|
139
|
+
@Action('greet')
|
|
140
|
+
greet(name: string): string {
|
|
141
|
+
return `Hello, ${name}!`
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@Action('add')
|
|
145
|
+
add(a: number, b: number): number {
|
|
146
|
+
return a + b
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Regular methods are NOT proxied
|
|
150
|
+
getVersion(): string {
|
|
151
|
+
return '1.0.0'
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
158
|
+
// Main process — sets up IPC handler with Roost
|
|
159
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
160
|
+
|
|
161
|
+
import { app, BrowserWindow, ipcMain } from 'electron'
|
|
162
|
+
import { Roost } from '@canlooks/roost'
|
|
163
|
+
|
|
164
|
+
app.whenReady().then(async () => {
|
|
165
|
+
const roost = await Roost.create({
|
|
166
|
+
named: { ApiController }
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// Handle incoming IPC calls
|
|
170
|
+
ipcMain.handle('@canlooks/roost-electron', async (_event, path, ...args) => {
|
|
171
|
+
const results = await roost.invoke(path, ...args)
|
|
172
|
+
return results[0] // Return the first result for single-action calls
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// ... create BrowserWindow, load renderer
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
181
|
+
// Renderer process — creates proxy and calls methods transparently
|
|
182
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
183
|
+
|
|
184
|
+
import { createRoostRenderer } from '@canlooks/roost-electron-renderer'
|
|
185
|
+
import { ipcRenderer } from 'electron'
|
|
186
|
+
|
|
187
|
+
async function main() {
|
|
188
|
+
const { ApiController: api } = await createRoostRenderer(
|
|
189
|
+
{ ApiController },
|
|
190
|
+
{ ipcRenderer }
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// These look like local calls but go through IPC to the main process:
|
|
194
|
+
const greeting = await api.greet('World') // → "Hello, World!"
|
|
195
|
+
const sum = await api.add(3, 4) // → 7
|
|
196
|
+
|
|
197
|
+
// Non-action methods are NOT proxied — they run locally:
|
|
198
|
+
const version = api.getVersion() // → "1.0.0" (local call)
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Multiple Controllers
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const { UserController, OrderController } = await createRoostRenderer(
|
|
206
|
+
{ UserController, OrderController },
|
|
207
|
+
{ ipcRenderer }
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
// Each controller's @Action methods are independently proxied
|
|
211
|
+
const users = await UserController.list()
|
|
212
|
+
const order = await OrderController.findById(42)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Custom IPC Channel
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
const { ApiController: api } = await createRoostRenderer(
|
|
219
|
+
{ ApiController },
|
|
220
|
+
{
|
|
221
|
+
ipcRenderer,
|
|
222
|
+
channel: 'my-custom-channel' // Must match main process ipcMain.handle()
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Controllers Without Actions
|
|
228
|
+
|
|
229
|
+
Controllers with no `@Action` methods are handled gracefully — the instance is returned as-is with no method rewriting:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
@Controller('config')
|
|
233
|
+
class ConfigController {
|
|
234
|
+
theme = 'dark'
|
|
235
|
+
setTheme(t: string) { this.theme = t }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const { ConfigController: config } = await createRoostRenderer(
|
|
239
|
+
{ ConfigController },
|
|
240
|
+
{ ipcRenderer }
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
console.log(config.theme) // 'dark' — normal property access
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## TypeScript Support
|
|
247
|
+
|
|
248
|
+
The package is written in TypeScript and ships with full type declarations. The return type of `createRoostRenderer` is **fully inferred** from the input controller map — each property is correctly typed as an instance of the corresponding class.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
const renderers = await createRoostRenderer(
|
|
252
|
+
{ ApiController, UserController },
|
|
253
|
+
{ ipcRenderer }
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
// TypeScript knows these types:
|
|
257
|
+
renderers.ApiController.greet(name: string): Promise<string>
|
|
258
|
+
renderers.UserController.list(): Promise<string[]>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The `ComponentType` constraint ensures only class constructors (not plain objects or primitives) can be passed as controllers.
|
|
262
|
+
|
|
263
|
+
## Main Process Integration
|
|
264
|
+
|
|
265
|
+
This package handles the **renderer side** of the IPC bridge. The main process must:
|
|
266
|
+
|
|
267
|
+
1. Create a Roost app with the same controllers.
|
|
268
|
+
2. Register an `ipcMain.handle()` listener on the same channel.
|
|
269
|
+
3. Call `roost.invoke(path, ...args)` and return the result.
|
|
270
|
+
|
|
271
|
+
See the [Roost framework documentation](https://github.com/canlooks/roost) for details on main-process setup, including the `@canlooks/roost-electron` package which provides main-process IPC handling out of the box.
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
MIT © [C.CanLiang](https://github.com/canlooks)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IpcRenderer } from 'electron';
|
|
2
|
+
import { ComponentType } from '@canlooks/roost';
|
|
3
|
+
export type CreateRoostRendererOptions = {
|
|
4
|
+
channel?: string;
|
|
5
|
+
ipcRenderer: IpcRenderer;
|
|
6
|
+
};
|
|
7
|
+
export declare function createRoostRenderer<T extends Record<string, ComponentType>>(controllers: T, options: CreateRoostRendererOptions): Promise<{ [K in keyof T]: InstanceType<T[K]>; }>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRoostRenderer = createRoostRenderer;
|
|
4
|
+
const roost_1 = require("@canlooks/roost");
|
|
5
|
+
const rewriteAction_1 = require("./rewriteAction");
|
|
6
|
+
async function createRoostRenderer(controllers, options) {
|
|
7
|
+
const renderers = {};
|
|
8
|
+
const app = await roost_1.Roost.create({
|
|
9
|
+
named: controllers,
|
|
10
|
+
readOnly: true
|
|
11
|
+
});
|
|
12
|
+
const instances = await Promise.all(Object.keys(controllers).map(async (name) => {
|
|
13
|
+
return renderers[name] = await app.container.get(name);
|
|
14
|
+
}));
|
|
15
|
+
(0, rewriteAction_1.rewriteActions)(instances, options);
|
|
16
|
+
return renderers;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './createRenderer';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rewriteActions = rewriteActions;
|
|
4
|
+
const roost_1 = require("@canlooks/roost");
|
|
5
|
+
function rewriteActions(instances, options) {
|
|
6
|
+
instances.forEach(instance => {
|
|
7
|
+
const completeKeyMap = (0, roost_1.getActionsKey)(instance);
|
|
8
|
+
if (completeKeyMap) {
|
|
9
|
+
for (const [property, { path, pattern }] of completeKeyMap) {
|
|
10
|
+
const key = path || pattern;
|
|
11
|
+
if (key) {
|
|
12
|
+
instance[property] = (...args) => {
|
|
13
|
+
return options.ipcRenderer.invoke(options.channel || '@canlooks/roost-electron', key, ...args);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IpcRenderer } from 'electron';
|
|
2
|
+
import { ComponentType } from '@canlooks/roost';
|
|
3
|
+
export type CreateRoostRendererOptions = {
|
|
4
|
+
channel?: string;
|
|
5
|
+
ipcRenderer: IpcRenderer;
|
|
6
|
+
};
|
|
7
|
+
export declare function createRoostRenderer<T extends Record<string, ComponentType>>(controllers: T, options: CreateRoostRendererOptions): Promise<{ [K in keyof T]: InstanceType<T[K]>; }>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Roost } from '@canlooks/roost';
|
|
2
|
+
import { rewriteActions } from './rewriteAction.js';
|
|
3
|
+
export async function createRoostRenderer(controllers, options) {
|
|
4
|
+
const renderers = {};
|
|
5
|
+
const app = await Roost.create({
|
|
6
|
+
named: controllers,
|
|
7
|
+
readOnly: true
|
|
8
|
+
});
|
|
9
|
+
const instances = await Promise.all(Object.keys(controllers).map(async (name) => {
|
|
10
|
+
return renderers[name] = await app.container.get(name);
|
|
11
|
+
}));
|
|
12
|
+
rewriteActions(instances, options);
|
|
13
|
+
return renderers;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './createRenderer.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './createRenderer.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getActionsKey } from '@canlooks/roost';
|
|
2
|
+
export function rewriteActions(instances, options) {
|
|
3
|
+
instances.forEach(instance => {
|
|
4
|
+
const completeKeyMap = getActionsKey(instance);
|
|
5
|
+
if (completeKeyMap) {
|
|
6
|
+
for (const [property, { path, pattern }] of completeKeyMap) {
|
|
7
|
+
const key = path || pattern;
|
|
8
|
+
if (key) {
|
|
9
|
+
instance[property] = (...args) => {
|
|
10
|
+
return options.ipcRenderer.invoke(options.channel || '@canlooks/roost-electron', key, ...args);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@canlooks/roost-electron-renderer",
|
|
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
|
+
"test": "vitest run"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@canlooks/roost": "^0.0.1",
|
|
42
|
+
"tslib": "^2.8.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/express": "^5.0.6",
|
|
46
|
+
"@types/node": "^25.9.1",
|
|
47
|
+
"@types/react": "^19.2.17",
|
|
48
|
+
"@types/react-dom": "^19.2.3",
|
|
49
|
+
"electron": "^42.3.0",
|
|
50
|
+
"react": "^19.2.7",
|
|
51
|
+
"react-dom": "^19.2.7",
|
|
52
|
+
"tsc-alias": "^1.8.17",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"vite": "^8.0.16",
|
|
55
|
+
"vitest": "^4.1.7"
|
|
56
|
+
}
|
|
57
|
+
}
|