electron-effect-rpc 0.2.0 → 0.4.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/README.md +95 -187
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/kit.d.ts +70 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +134 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +53 -4
- package/dist/preload.d.ts +4 -0
- package/dist/preload.d.ts.map +1 -1
- package/dist/preload.js +26 -1
- package/dist/renderer.d.ts +2 -2
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +100 -77
- package/dist/types.d.ts +13 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
# electron-effect-rpc
|
|
2
2
|
|
|
3
|
-
Typed IPC RPC for Electron, built on Effect and @effect/schema.
|
|
4
|
-
lets you define a shared contract, generate a typed RPC client in the renderer,
|
|
5
|
-
register handlers in the main process, and stream typed events across processes.
|
|
3
|
+
Typed IPC RPC for Electron, built on Effect and @effect/schema.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
The ergonomic default is now a single shared `createIpcKit` configuration that
|
|
6
|
+
you reuse in main, preload, and renderer code. Low-level subpath APIs still
|
|
7
|
+
exist and remain fully supported.
|
|
8
|
+
|
|
9
|
+
This package is ESM-only. It targets modern Electron runtimes and assumes an
|
|
10
|
+
ESM-capable build pipeline.
|
|
9
11
|
|
|
10
12
|
## Features
|
|
11
13
|
- Single shared contract for methods and events.
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- Effect-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
14
|
+
- Single shared kit config to eliminate cross-process prefix drift.
|
|
15
|
+
- End-to-end schema validation at IPC boundaries.
|
|
16
|
+
- Effect-first renderer RPC with typed domain and defect channels.
|
|
17
|
+
- Effect-native main handlers with explicit runtime injection.
|
|
18
|
+
- Explicit lifecycle handles and bounded event queue backpressure.
|
|
17
19
|
- Structured diagnostics hooks for decode/protocol/dispatch failures.
|
|
18
20
|
|
|
19
21
|
## Requirements
|
|
20
22
|
- Electron with context isolation enabled.
|
|
21
|
-
- ESM-capable
|
|
23
|
+
- ESM-capable bundling.
|
|
22
24
|
- Peer dependencies: `effect`, `@effect/schema`, `electron`.
|
|
23
25
|
|
|
24
26
|
## Installation
|
|
@@ -26,31 +28,12 @@ uses Electron 38) and assumes ESM-capable bundling.
|
|
|
26
28
|
bun add electron-effect-rpc effect @effect/schema
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
and let the workspace resolver handle the rest.
|
|
31
|
-
|
|
32
|
-
## Core Concepts
|
|
33
|
-
|
|
34
|
-
### Communication directions
|
|
35
|
-
|
|
36
|
-
This library provides two communication patterns for Electron IPC:
|
|
37
|
-
|
|
38
|
-
| Direction | Mechanism | Pattern | Use case |
|
|
39
|
-
|-----------|-----------|---------|----------|
|
|
40
|
-
| **Renderer → Main** | RPC methods | Request/response | Fetching data, triggering actions, calling main process APIs |
|
|
41
|
-
| **Main → Renderer** | Event bus | Push/broadcast | Progress updates, state changes, background task notifications |
|
|
42
|
-
|
|
43
|
-
**RPC methods** are for when the renderer needs something from the main process. The renderer calls a method and awaits a typed response.
|
|
44
|
-
|
|
45
|
-
**Events** are for when the main process needs to notify the renderer. The main process emits events whenever it wants, and the renderer subscribes to receive them.
|
|
46
|
-
|
|
47
|
-
### Defining methods and events
|
|
48
|
-
|
|
49
|
-
Define methods and events using schema-based helpers:
|
|
31
|
+
## Quickstart (Kit-First)
|
|
50
32
|
|
|
33
|
+
### 1) Define contract and kit once
|
|
51
34
|
```ts
|
|
52
35
|
import * as S from "@effect/schema/Schema";
|
|
53
|
-
import { defineContract, event, rpc } from "electron-effect-rpc
|
|
36
|
+
import { createIpcKit, defineContract, event, rpc } from "electron-effect-rpc";
|
|
54
37
|
|
|
55
38
|
export const GetAppVersion = rpc(
|
|
56
39
|
"GetAppVersion",
|
|
@@ -67,218 +50,143 @@ export const WorkUnitProgress = event(
|
|
|
67
50
|
})
|
|
68
51
|
);
|
|
69
52
|
|
|
70
|
-
const
|
|
71
|
-
|
|
53
|
+
const contract = defineContract({
|
|
54
|
+
methods: [GetAppVersion] as const,
|
|
55
|
+
events: [WorkUnitProgress] as const,
|
|
56
|
+
});
|
|
72
57
|
|
|
73
|
-
export const
|
|
58
|
+
export const ipc = createIpcKit({
|
|
59
|
+
contract,
|
|
60
|
+
channelPrefix: { rpc: "rpc/", event: "event/" },
|
|
61
|
+
bridge: { global: "api" },
|
|
62
|
+
decode: { rpc: "envelope", events: "safe" },
|
|
63
|
+
});
|
|
74
64
|
```
|
|
75
65
|
|
|
76
|
-
###
|
|
77
|
-
Error schemas should be `Schema.TaggedError` classes. If a method does not
|
|
78
|
-
declare an error schema, it uses `NoError` and the error channel is `never`.
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
import * as S from "@effect/schema/Schema";
|
|
82
|
-
import { rpc } from "electron-effect-rpc/contract";
|
|
83
|
-
|
|
84
|
-
export class FileReadError extends S.TaggedError<FileReadError>()("FileReadError", {
|
|
85
|
-
message: S.String,
|
|
86
|
-
path: S.String,
|
|
87
|
-
}) {}
|
|
88
|
-
|
|
89
|
-
export const ReadTextFile = rpc(
|
|
90
|
-
"ReadTextFile",
|
|
91
|
-
S.Struct({ path: S.String }),
|
|
92
|
-
S.Struct({ content: S.String }),
|
|
93
|
-
FileReadError
|
|
94
|
-
);
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Usage
|
|
98
|
-
|
|
99
|
-
### Main process: register handlers
|
|
66
|
+
### 2) Main process
|
|
100
67
|
```ts
|
|
101
68
|
import { app, ipcMain } from "electron";
|
|
102
69
|
import { Effect } from "effect";
|
|
103
70
|
import * as Runtime from "effect/Runtime";
|
|
104
|
-
import {
|
|
105
|
-
import { contract, WorkUnitProgress } from "./contract.ts";
|
|
106
|
-
|
|
107
|
-
const implementations = {
|
|
108
|
-
GetAppVersion: () => Effect.succeed({ version: app.getVersion() }),
|
|
109
|
-
};
|
|
71
|
+
import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
|
|
110
72
|
|
|
111
|
-
const
|
|
73
|
+
const mainRpc = ipc.main({
|
|
74
|
+
ipcMain,
|
|
75
|
+
handlers: {
|
|
76
|
+
GetAppVersion: () => Effect.succeed({ version: app.getVersion() }),
|
|
77
|
+
},
|
|
112
78
|
runtime: Runtime.defaultRuntime,
|
|
113
|
-
});
|
|
114
|
-
endpoint.start();
|
|
115
|
-
|
|
116
|
-
const publisher = createEventPublisher(contract, {
|
|
117
79
|
getWindow: () => mainWindow,
|
|
118
80
|
});
|
|
119
|
-
publisher.start();
|
|
120
81
|
|
|
121
|
-
|
|
82
|
+
mainRpc.start();
|
|
83
|
+
|
|
84
|
+
void Effect.runPromise(mainRpc.publish(WorkUnitProgress, {
|
|
122
85
|
requestId: "req-1",
|
|
123
|
-
chunk: "
|
|
86
|
+
chunk: "starting",
|
|
124
87
|
done: false,
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Pass the runtime used to execute handler effects:
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
import * as Runtime from "effect/Runtime";
|
|
132
|
-
import { createRpcEndpoint } from "electron-effect-rpc/main";
|
|
133
|
-
import { contract } from "./contract.ts";
|
|
134
|
-
|
|
135
|
-
const endpoint = createRpcEndpoint(contract, ipcMain, implementations, {
|
|
136
|
-
runtime: Runtime.defaultRuntime,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
endpoint.start();
|
|
88
|
+
}));
|
|
140
89
|
```
|
|
141
90
|
|
|
142
|
-
### Preload
|
|
91
|
+
### 3) Preload
|
|
143
92
|
```ts
|
|
144
|
-
import {
|
|
93
|
+
import { ipc } from "./shared-ipc.ts";
|
|
145
94
|
|
|
146
|
-
|
|
95
|
+
ipc.preload().expose();
|
|
147
96
|
```
|
|
148
97
|
|
|
149
|
-
|
|
150
|
-
- RPC global: `window.rpc.invoke(method, payload)`
|
|
151
|
-
- Events global: `window.events.subscribe(name, handler)`
|
|
152
|
-
- Channel prefix: `rpc/` and `event/`
|
|
98
|
+
This exposes one global by default: `window.api`.
|
|
153
99
|
|
|
154
|
-
|
|
100
|
+
### 4) Renderer
|
|
155
101
|
```ts
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
eventsGlobal: "rpcEvents",
|
|
159
|
-
channelPrefix: { rpc: "rpc/", event: "events/" },
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Or use low-level bridge adapters for custom exposure:
|
|
164
|
-
```ts
|
|
165
|
-
import { createBridgeAdapters } from "electron-effect-rpc/preload";
|
|
166
|
-
|
|
167
|
-
const bridge = createBridgeAdapters();
|
|
168
|
-
// bridge.invoke(method, payload)
|
|
169
|
-
// bridge.subscribe(name, handler)
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Renderer: create client and subscriber
|
|
173
|
-
```ts
|
|
174
|
-
import { createRpcClient, createEventSubscriber } from "electron-effect-rpc/renderer";
|
|
175
|
-
import { contract, WorkUnitProgress } from "./contract.ts";
|
|
176
|
-
|
|
177
|
-
const client = createRpcClient(contract, { invoke: window.rpc.invoke });
|
|
178
|
-
const events = createEventSubscriber(contract, {
|
|
179
|
-
subscribe: window.events.subscribe,
|
|
180
|
-
decodeMode: "safe", // default
|
|
181
|
-
});
|
|
102
|
+
import { Effect } from "effect";
|
|
103
|
+
import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
|
|
182
104
|
|
|
183
|
-
const {
|
|
105
|
+
const { client, events } = ipc.renderer(window.api);
|
|
106
|
+
const { version } = await Effect.runPromise(client.GetAppVersion());
|
|
184
107
|
|
|
185
|
-
events.subscribe(WorkUnitProgress, (payload) => {
|
|
108
|
+
const unsubscribe = events.subscribe(WorkUnitProgress, (payload) => {
|
|
186
109
|
console.log(payload.chunk);
|
|
187
110
|
});
|
|
188
|
-
```
|
|
189
111
|
|
|
190
|
-
|
|
191
|
-
|
|
112
|
+
// later
|
|
113
|
+
unsubscribe();
|
|
114
|
+
events.dispose();
|
|
115
|
+
```
|
|
192
116
|
|
|
117
|
+
### 5) Window typing
|
|
193
118
|
```ts
|
|
194
119
|
declare global {
|
|
195
120
|
interface Window {
|
|
196
|
-
|
|
121
|
+
api: {
|
|
197
122
|
invoke: (method: string, payload: unknown) => Promise<unknown>;
|
|
198
|
-
};
|
|
199
|
-
events: {
|
|
200
123
|
subscribe: (name: string, handler: (payload: unknown) => void) => () => void;
|
|
201
124
|
};
|
|
202
125
|
}
|
|
203
126
|
}
|
|
204
127
|
```
|
|
205
128
|
|
|
206
|
-
##
|
|
129
|
+
## Error Model
|
|
207
130
|
|
|
208
|
-
|
|
209
|
-
|
|
131
|
+
Domain failures are modeled with tagged error schemas and are surfaced in the
|
|
132
|
+
Effect error channel as those same tagged values. Unexpected failures,
|
|
133
|
+
transport defects, and protocol mismatches are surfaced as `RpcDefectError`,
|
|
134
|
+
which includes a stable `code` discriminator:
|
|
135
|
+
`request_encoding_failed`, `invoke_failed`,
|
|
136
|
+
`success_payload_decoding_failed`, `failure_payload_decoding_failed`,
|
|
137
|
+
`noerror_contract_violation`, `invalid_response_envelope`,
|
|
138
|
+
`legacy_decode_failed`, and `remote_defect`.
|
|
210
139
|
|
|
211
|
-
|
|
212
|
-
import { createRpcClient } from "electron-effect-rpc/renderer";
|
|
213
|
-
import { createInvokeStub } from "electron-effect-rpc/testing";
|
|
214
|
-
import { contract } from "./contract.ts";
|
|
215
|
-
|
|
216
|
-
const invoke = createInvokeStub(async (method, payload) => {
|
|
217
|
-
return {
|
|
218
|
-
type: "success",
|
|
219
|
-
data: { version: "1.0.0" },
|
|
220
|
-
};
|
|
221
|
-
});
|
|
140
|
+
## Breaking Changes
|
|
222
141
|
|
|
223
|
-
|
|
224
|
-
|
|
142
|
+
Renderer RPC methods now return `Effect.Effect` instead of `Promise`, and
|
|
143
|
+
`IpcMainHandle.emit` was removed in favor of `publish`.
|
|
225
144
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
145
|
+
Before:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const result = await client.GetAppVersion();
|
|
149
|
+
await mainRpc.emit(WorkUnitProgress, payload);
|
|
229
150
|
```
|
|
230
151
|
|
|
231
|
-
|
|
232
|
-
You can stub `IpcMainLike` and collect registered handlers:
|
|
152
|
+
After:
|
|
233
153
|
|
|
234
154
|
```ts
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
import type { IpcMainLike } from "electron-effect-rpc/types";
|
|
238
|
-
import { contract } from "./contract.ts";
|
|
239
|
-
|
|
240
|
-
const handlers = new Map<string, (event: unknown, payload: unknown) => unknown>();
|
|
241
|
-
const ipcMainStub: IpcMainLike = {
|
|
242
|
-
handle: (channel, handler) => {
|
|
243
|
-
handlers.set(channel, handler);
|
|
244
|
-
},
|
|
245
|
-
removeHandler: (channel) => {
|
|
246
|
-
handlers.delete(channel);
|
|
247
|
-
},
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const endpoint = createRpcEndpoint(contract, ipcMainStub, implementations, {
|
|
251
|
-
runtime: Runtime.defaultRuntime,
|
|
252
|
-
});
|
|
253
|
-
endpoint.start();
|
|
155
|
+
const result = await Effect.runPromise(client.GetAppVersion());
|
|
156
|
+
await Effect.runPromise(mainRpc.publish(WorkUnitProgress, payload));
|
|
254
157
|
```
|
|
255
158
|
|
|
256
|
-
##
|
|
257
|
-
- If a handler fails with a typed domain error, the renderer client rejects
|
|
258
|
-
with that error instance.
|
|
259
|
-
- If a handler dies or throws a defect, the renderer client rejects with
|
|
260
|
-
`RpcDefectError`.
|
|
159
|
+
## Low-Level APIs (Still Supported)
|
|
261
160
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
Entry points:
|
|
161
|
+
If you need direct control, keep using subpath entry points:
|
|
265
162
|
- `electron-effect-rpc/contract`
|
|
266
|
-
- `rpc`, `event`, `defineContract`, `exitSchemaFor`, `SchemaNoContext`, `NoError`
|
|
267
|
-
- `electron-effect-rpc/types`
|
|
268
|
-
- Type aliases such as `Implementations`, `RpcClient`, `RpcEventPublisher`, `IpcMainLike`
|
|
269
163
|
- `electron-effect-rpc/main`
|
|
270
|
-
- `createRpcEndpoint`, `createEventPublisher`
|
|
271
164
|
- `electron-effect-rpc/renderer`
|
|
272
|
-
- `createRpcClient`, `createEventSubscriber`, `RpcDefectError`
|
|
273
165
|
- `electron-effect-rpc/preload`
|
|
274
|
-
|
|
166
|
+
- `electron-effect-rpc/types`
|
|
275
167
|
- `electron-effect-rpc/testing`
|
|
276
|
-
|
|
168
|
+
|
|
169
|
+
## Root API Surface
|
|
170
|
+
|
|
171
|
+
The root entry point exports:
|
|
172
|
+
- `createIpcKit`
|
|
173
|
+
- `rpc`, `event`, `defineContract`, `NoError`
|
|
174
|
+
- Types: `IpcKit`, `IpcKitOptions`, `IpcMainHandle`, `IpcBridge`, `IpcBridgeGlobal`
|
|
175
|
+
|
|
176
|
+
Low-level factories like `createRpcClient` remain subpath-only by design.
|
|
177
|
+
|
|
178
|
+
## Tutorials
|
|
179
|
+
|
|
180
|
+
For deeper walkthroughs and production guidance:
|
|
181
|
+
- [Tutorial Index](./docs/tutorials/README.md)
|
|
182
|
+
- [First RPC: Main + Preload + Renderer](./docs/tutorials/01-first-rpc.md)
|
|
183
|
+
- [Typed Errors, Defects, and Diagnostics](./docs/tutorials/02-typed-errors-defects-diagnostics.md)
|
|
184
|
+
- [Events, Lifecycle, and Backpressure](./docs/tutorials/03-events-lifecycle-backpressure.md)
|
|
277
185
|
|
|
278
186
|
## Conventions
|
|
279
187
|
- Relative imports use `.ts` extensions.
|
|
280
188
|
- Package imports are extensionless.
|
|
281
|
-
- No `index.ts` barrel files.
|
|
189
|
+
- No `index.ts` barrel files in subpath modules.
|
|
282
190
|
|
|
283
191
|
## License
|
|
284
192
|
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EACV,SAAS,EACT,eAAe,EACf,MAAM,EACN,aAAa,EACb,aAAa,GACd,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
package/dist/kit.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type * as Runtime from "effect/Runtime";
|
|
3
|
+
import type { AnyEvent, AnyMethod, RpcContract, RpcEventPayload } from "./contract.ts";
|
|
4
|
+
import { type ChannelPrefix, type EventDecodeMode, type EventPublisherDiagnostics, type EventSubscribe, type EventSubscriber, type IpcMainLike, type Implementations, type RendererWindowLike, type RpcClient, type RpcEndpoint, type RpcEndpointDiagnostics, type RpcEventPublisher, type RpcInvoke, type RpcResponseDecodeMode } from "./types.ts";
|
|
5
|
+
export type IpcBridge = {
|
|
6
|
+
readonly invoke: RpcInvoke;
|
|
7
|
+
readonly subscribe: EventSubscribe;
|
|
8
|
+
};
|
|
9
|
+
export type IpcBridgeGlobal<Name extends string = "api"> = {
|
|
10
|
+
readonly [K in Name]: IpcBridge;
|
|
11
|
+
};
|
|
12
|
+
export type IpcKitOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
|
|
13
|
+
readonly contract: C;
|
|
14
|
+
readonly channelPrefix?: ChannelPrefix;
|
|
15
|
+
readonly bridge?: {
|
|
16
|
+
readonly global?: string;
|
|
17
|
+
};
|
|
18
|
+
readonly decode?: {
|
|
19
|
+
readonly rpc?: RpcResponseDecodeMode;
|
|
20
|
+
readonly events?: EventDecodeMode;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
type IpcMainOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>, R> = {
|
|
24
|
+
readonly ipcMain: IpcMainLike;
|
|
25
|
+
readonly handlers: Implementations<C, R>;
|
|
26
|
+
readonly runtime: Runtime.Runtime<R>;
|
|
27
|
+
readonly getWindow: () => RendererWindowLike | null;
|
|
28
|
+
readonly maxQueueSize?: number;
|
|
29
|
+
readonly diagnostics?: {
|
|
30
|
+
readonly rpc?: RpcEndpointDiagnostics;
|
|
31
|
+
readonly events?: EventPublisherDiagnostics;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export type IpcMainHandle<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
|
|
35
|
+
readonly endpoint: RpcEndpoint;
|
|
36
|
+
readonly publisher: RpcEventPublisher<C>;
|
|
37
|
+
readonly start: () => void;
|
|
38
|
+
readonly stop: () => void;
|
|
39
|
+
readonly dispose: () => void;
|
|
40
|
+
readonly isRunning: () => boolean;
|
|
41
|
+
readonly publish: <E extends C["events"][number]>(event: E, payload: RpcEventPayload<E>) => Effect.Effect<void, never>;
|
|
42
|
+
readonly stats: () => {
|
|
43
|
+
readonly queued: number;
|
|
44
|
+
readonly dropped: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
|
|
48
|
+
readonly contract: C;
|
|
49
|
+
readonly config: {
|
|
50
|
+
readonly channelPrefix: ChannelPrefix;
|
|
51
|
+
readonly bridgeGlobal: string;
|
|
52
|
+
readonly rpcDecodeMode: RpcResponseDecodeMode;
|
|
53
|
+
readonly eventDecodeMode: EventDecodeMode;
|
|
54
|
+
};
|
|
55
|
+
readonly main: <R>(options: IpcMainOptions<C, R>) => IpcMainHandle<C>;
|
|
56
|
+
readonly preload: (options?: {
|
|
57
|
+
readonly global?: string;
|
|
58
|
+
}) => {
|
|
59
|
+
readonly global: string;
|
|
60
|
+
readonly bridge: IpcBridge;
|
|
61
|
+
readonly expose: () => void;
|
|
62
|
+
};
|
|
63
|
+
readonly renderer: (bridge: IpcBridge) => {
|
|
64
|
+
readonly client: RpcClient<C>;
|
|
65
|
+
readonly events: EventSubscriber<C>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export declare function createIpcKit<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(options: IpcKitOptions<RpcContract<Methods, Events>>): IpcKit<RpcContract<Methods, Events>>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
|
package/dist/kit.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { createEventPublisher, createRpcEndpoint } from "./main.js";
|
|
3
|
+
import { exposeIpcBridge, createBridgeAdapters } from "./preload.js";
|
|
4
|
+
import { createEventSubscriber, createRpcClient } from "./renderer.js";
|
|
5
|
+
import { defaultChannelPrefix, } from "./types.js";
|
|
6
|
+
export function createIpcKit(options) {
|
|
7
|
+
const contract = options.contract;
|
|
8
|
+
const channelPrefix = options.channelPrefix
|
|
9
|
+
? { ...options.channelPrefix }
|
|
10
|
+
: { ...defaultChannelPrefix };
|
|
11
|
+
const bridgeGlobal = options.bridge?.global ?? "api";
|
|
12
|
+
const rpcDecodeMode = options.decode?.rpc ?? "envelope";
|
|
13
|
+
const eventDecodeMode = options.decode?.events ?? "safe";
|
|
14
|
+
const main = (mainOptions) => {
|
|
15
|
+
const endpoint = createRpcEndpoint(contract, mainOptions.ipcMain, mainOptions.handlers, {
|
|
16
|
+
runtime: mainOptions.runtime,
|
|
17
|
+
channelPrefix,
|
|
18
|
+
diagnostics: mainOptions.diagnostics?.rpc,
|
|
19
|
+
});
|
|
20
|
+
const publisher = createEventPublisher(contract, {
|
|
21
|
+
getWindow: mainOptions.getWindow,
|
|
22
|
+
maxQueueSize: mainOptions.maxQueueSize,
|
|
23
|
+
channelPrefix,
|
|
24
|
+
diagnostics: mainOptions.diagnostics?.events,
|
|
25
|
+
});
|
|
26
|
+
function start() {
|
|
27
|
+
endpoint.start();
|
|
28
|
+
try {
|
|
29
|
+
publisher.start();
|
|
30
|
+
}
|
|
31
|
+
catch (cause) {
|
|
32
|
+
try {
|
|
33
|
+
endpoint.stop();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Best effort rollback.
|
|
37
|
+
}
|
|
38
|
+
throw cause;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function stop() {
|
|
42
|
+
let firstError;
|
|
43
|
+
try {
|
|
44
|
+
publisher.stop();
|
|
45
|
+
}
|
|
46
|
+
catch (cause) {
|
|
47
|
+
firstError ??= cause;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
endpoint.stop();
|
|
51
|
+
}
|
|
52
|
+
catch (cause) {
|
|
53
|
+
firstError ??= cause;
|
|
54
|
+
}
|
|
55
|
+
if (firstError !== undefined) {
|
|
56
|
+
throw firstError;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function dispose() {
|
|
60
|
+
let firstError;
|
|
61
|
+
try {
|
|
62
|
+
publisher.dispose();
|
|
63
|
+
}
|
|
64
|
+
catch (cause) {
|
|
65
|
+
firstError ??= cause;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
endpoint.dispose();
|
|
69
|
+
}
|
|
70
|
+
catch (cause) {
|
|
71
|
+
firstError ??= cause;
|
|
72
|
+
}
|
|
73
|
+
if (firstError !== undefined) {
|
|
74
|
+
throw firstError;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function isRunning() {
|
|
78
|
+
return endpoint.isRunning() && publisher.isRunning();
|
|
79
|
+
}
|
|
80
|
+
function publish(event, payload) {
|
|
81
|
+
return publisher.publish(event, payload);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
endpoint,
|
|
85
|
+
publisher,
|
|
86
|
+
start,
|
|
87
|
+
stop,
|
|
88
|
+
dispose,
|
|
89
|
+
isRunning,
|
|
90
|
+
publish,
|
|
91
|
+
stats: publisher.stats,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const preload = (preloadOptions) => {
|
|
95
|
+
const global = preloadOptions?.global ?? bridgeGlobal;
|
|
96
|
+
const bridge = createBridgeAdapters({
|
|
97
|
+
channelPrefix,
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
global,
|
|
101
|
+
bridge,
|
|
102
|
+
expose: () => {
|
|
103
|
+
exposeIpcBridge({
|
|
104
|
+
global,
|
|
105
|
+
channelPrefix,
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const renderer = (bridge) => {
|
|
111
|
+
return {
|
|
112
|
+
client: createRpcClient(contract, {
|
|
113
|
+
invoke: bridge.invoke,
|
|
114
|
+
rpcDecodeMode,
|
|
115
|
+
}),
|
|
116
|
+
events: createEventSubscriber(contract, {
|
|
117
|
+
subscribe: bridge.subscribe,
|
|
118
|
+
decodeMode: eventDecodeMode,
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
contract,
|
|
124
|
+
config: {
|
|
125
|
+
channelPrefix,
|
|
126
|
+
bridgeGlobal,
|
|
127
|
+
rpcDecodeMode,
|
|
128
|
+
eventDecodeMode,
|
|
129
|
+
},
|
|
130
|
+
main,
|
|
131
|
+
preload,
|
|
132
|
+
renderer,
|
|
133
|
+
};
|
|
134
|
+
}
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,eAAe,CAAC;AAQvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAmBpB,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,CAAC,GAAG,KAAK,EAET,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EACtC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EACjE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC7B,WAAW,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,eAAe,CAAC;AAQvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAmBpB,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,CAAC,GAAG,KAAK,EAET,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EACtC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EACjE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC7B,WAAW,CAgNb;AAmBD,wBAAgB,oBAAoB,CAClC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAE5C,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EACvC,OAAO,EAAE,qBAAqB,GAC7B,iBAAiB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAkMjD"}
|
package/dist/main.js
CHANGED
|
@@ -109,8 +109,23 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
109
109
|
if (running) {
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
const registeredChannels = [];
|
|
113
|
+
try {
|
|
114
|
+
for (const [channel, listener] of listeners) {
|
|
115
|
+
ipc.handle(channel, listener);
|
|
116
|
+
registeredChannels.push(channel);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (cause) {
|
|
120
|
+
for (const channel of registeredChannels) {
|
|
121
|
+
try {
|
|
122
|
+
ipc.removeHandler(channel);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Best-effort rollback: avoid leaving partial registration behind.
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
throw cause;
|
|
114
129
|
}
|
|
115
130
|
running = true;
|
|
116
131
|
}
|
|
@@ -118,17 +133,35 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
118
133
|
if (!running) {
|
|
119
134
|
return;
|
|
120
135
|
}
|
|
136
|
+
let firstError;
|
|
121
137
|
for (const channel of listeners.keys()) {
|
|
122
|
-
|
|
138
|
+
try {
|
|
139
|
+
ipc.removeHandler(channel);
|
|
140
|
+
}
|
|
141
|
+
catch (cause) {
|
|
142
|
+
firstError ??= cause;
|
|
143
|
+
}
|
|
123
144
|
}
|
|
124
145
|
running = false;
|
|
146
|
+
if (firstError !== undefined) {
|
|
147
|
+
throw firstError;
|
|
148
|
+
}
|
|
125
149
|
}
|
|
126
150
|
function dispose() {
|
|
127
151
|
if (disposed) {
|
|
128
152
|
return;
|
|
129
153
|
}
|
|
130
|
-
|
|
154
|
+
let stopError;
|
|
155
|
+
try {
|
|
156
|
+
stop();
|
|
157
|
+
}
|
|
158
|
+
catch (cause) {
|
|
159
|
+
stopError = cause;
|
|
160
|
+
}
|
|
131
161
|
disposed = true;
|
|
162
|
+
if (stopError !== undefined) {
|
|
163
|
+
throw stopError;
|
|
164
|
+
}
|
|
132
165
|
}
|
|
133
166
|
function isRunning() {
|
|
134
167
|
return running;
|
|
@@ -193,17 +226,33 @@ export function createEventPublisher(_contract, options) {
|
|
|
193
226
|
}
|
|
194
227
|
const window = options.getWindow();
|
|
195
228
|
if (!window || window.isDestroyed()) {
|
|
229
|
+
dropped += 1;
|
|
230
|
+
safelyCall(diagnostics?.onDroppedEvent, {
|
|
231
|
+
event: item.event.name,
|
|
232
|
+
payload: item.payload,
|
|
233
|
+
reason: "window_unavailable",
|
|
234
|
+
queued: queue.length,
|
|
235
|
+
dropped,
|
|
236
|
+
});
|
|
196
237
|
return;
|
|
197
238
|
}
|
|
198
239
|
try {
|
|
199
240
|
window.webContents.send(`${channelPrefix.event}${item.event.name}`, encoded);
|
|
200
241
|
}
|
|
201
242
|
catch (cause) {
|
|
243
|
+
dropped += 1;
|
|
202
244
|
safelyCall(diagnostics?.onDispatchFailure, {
|
|
203
245
|
event: item.event.name,
|
|
204
246
|
payload: item.payload,
|
|
205
247
|
cause,
|
|
206
248
|
});
|
|
249
|
+
safelyCall(diagnostics?.onDroppedEvent, {
|
|
250
|
+
event: item.event.name,
|
|
251
|
+
payload: item.payload,
|
|
252
|
+
reason: "dispatch_failed",
|
|
253
|
+
queued: queue.length,
|
|
254
|
+
dropped,
|
|
255
|
+
});
|
|
207
256
|
}
|
|
208
257
|
}
|
|
209
258
|
function drain() {
|
package/dist/preload.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ export type BridgeExposureOptions = BridgeAdaptersOptions & {
|
|
|
10
10
|
readonly rpcGlobal?: string;
|
|
11
11
|
readonly eventsGlobal?: string;
|
|
12
12
|
};
|
|
13
|
+
export type IpcBridgeExposureOptions = BridgeAdaptersOptions & {
|
|
14
|
+
readonly global?: string;
|
|
15
|
+
};
|
|
13
16
|
export declare function createBridgeAdapters(options?: BridgeAdaptersOptions): BridgeAdapters;
|
|
14
17
|
export declare function exposeRpcBridge(options?: BridgeExposureOptions): void;
|
|
18
|
+
export declare function exposeIpcBridge(options?: IpcBridgeExposureOptions): void;
|
|
15
19
|
//# sourceMappingURL=preload.d.ts.map
|
package/dist/preload.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preload.d.ts","sourceRoot":"","sources":["../src/preload.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"preload.d.ts","sourceRoot":"","sources":["../src/preload.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,GAAG;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,GAAG;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAwCF,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAuBhB;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAgBrE;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAYxE"}
|
package/dist/preload.js
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as electronModule from "electron";
|
|
2
2
|
import { defaultChannelPrefix, } from "./types.js";
|
|
3
|
+
function resolveElectronRendererBindings() {
|
|
4
|
+
const moduleDefault = electronModule.default;
|
|
5
|
+
const source = moduleDefault && typeof moduleDefault === "object"
|
|
6
|
+
? moduleDefault
|
|
7
|
+
: electronModule;
|
|
8
|
+
const contextBridge = source.contextBridge;
|
|
9
|
+
const ipcRenderer = source.ipcRenderer;
|
|
10
|
+
if (!contextBridge || !ipcRenderer) {
|
|
11
|
+
throw new Error("electron-effect-rpc/preload requires Electron preload runtime bindings.");
|
|
12
|
+
}
|
|
13
|
+
return { contextBridge, ipcRenderer };
|
|
14
|
+
}
|
|
3
15
|
export function createBridgeAdapters(options) {
|
|
4
16
|
const channelPrefix = options?.channelPrefix ?? defaultChannelPrefix;
|
|
17
|
+
const { ipcRenderer } = resolveElectronRendererBindings();
|
|
5
18
|
const invoke = (method, payload) => ipcRenderer.invoke(`${channelPrefix.rpc}${method}`, payload);
|
|
6
19
|
const subscribe = (event, listener) => {
|
|
7
20
|
const wrapped = (_event, payload) => listener(payload);
|
|
@@ -19,6 +32,7 @@ export function createBridgeAdapters(options) {
|
|
|
19
32
|
export function exposeRpcBridge(options) {
|
|
20
33
|
const rpcGlobal = options?.rpcGlobal ?? "rpc";
|
|
21
34
|
const eventsGlobal = options?.eventsGlobal ?? "events";
|
|
35
|
+
const { contextBridge } = resolveElectronRendererBindings();
|
|
22
36
|
const adapters = createBridgeAdapters({
|
|
23
37
|
channelPrefix: options?.channelPrefix,
|
|
24
38
|
});
|
|
@@ -29,3 +43,14 @@ export function exposeRpcBridge(options) {
|
|
|
29
43
|
subscribe: adapters.subscribe,
|
|
30
44
|
});
|
|
31
45
|
}
|
|
46
|
+
export function exposeIpcBridge(options) {
|
|
47
|
+
const global = options?.global ?? "api";
|
|
48
|
+
const { contextBridge } = resolveElectronRendererBindings();
|
|
49
|
+
const adapters = createBridgeAdapters({
|
|
50
|
+
channelPrefix: options?.channelPrefix,
|
|
51
|
+
});
|
|
52
|
+
contextBridge.exposeInMainWorld(global, {
|
|
53
|
+
invoke: adapters.invoke,
|
|
54
|
+
subscribe: adapters.subscribe,
|
|
55
|
+
});
|
|
56
|
+
}
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type RpcContract } from "./contract.ts";
|
|
2
2
|
import { type AnyEvent, type AnyMethod, type EventSubscriber, type EventSubscriberOptions, type RpcClient, type RpcClientOptions } from "./types.ts";
|
|
3
|
-
export declare function createRpcClient<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(contract: RpcContract<Methods, Events>, options
|
|
4
|
-
export declare function createEventSubscriber<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(contract: RpcContract<Methods, Events>, options
|
|
3
|
+
export declare function createRpcClient<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(contract: RpcContract<Methods, Events>, options: RpcClientOptions): RpcClient<RpcContract<Methods, Events>>;
|
|
4
|
+
export declare function createEventSubscriber<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(contract: RpcContract<Methods, Events>, options: EventSubscriberOptions): EventSubscriber<RpcContract<Methods, Events>>;
|
|
5
5
|
export { RpcDefectError } from "./types.ts";
|
|
6
6
|
//# sourceMappingURL=renderer.d.ts.map
|
package/dist/renderer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAIjB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAIjB,MAAM,eAAe,CAAC;AAOvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAGtB,MAAM,YAAY,CAAC;AAuEpB,wBAAgB,eAAe,CAC7B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAE5C,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EACtC,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CA0KzC;AAqBD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAE5C,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,EACtC,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAyF/C;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/renderer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as S from "@effect/schema/Schema";
|
|
2
|
-
import { Cause, Exit } from "effect";
|
|
2
|
+
import { Cause, Effect, Exit } from "effect";
|
|
3
3
|
import { exitSchemaFor, isNoErrorSchema, } from "./contract.js";
|
|
4
|
-
import { formatUnknown, parseRpcResponseEnvelope, safelyCall } from "./protocol.js";
|
|
4
|
+
import { formatUnknown, parseRpcResponseEnvelope, safelyCall, } from "./protocol.js";
|
|
5
5
|
import { RpcDefectError, } from "./types.js";
|
|
6
6
|
function requireInvoke(options) {
|
|
7
7
|
if (!options?.invoke) {
|
|
@@ -15,110 +15,124 @@ function requireSubscribe(options) {
|
|
|
15
15
|
}
|
|
16
16
|
return options.subscribe;
|
|
17
17
|
}
|
|
18
|
+
function rpcDefect(code, message, cause) {
|
|
19
|
+
return new RpcDefectError(code, message, cause);
|
|
20
|
+
}
|
|
18
21
|
function decodeLegacyExit(method, raw) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const failureOption = Cause.failureOption(exit.cause);
|
|
26
|
-
if (failureOption._tag === "Some") {
|
|
27
|
-
throw failureOption.value;
|
|
28
|
-
}
|
|
29
|
-
const defectOption = Cause.dieOption(exit.cause);
|
|
30
|
-
if (defectOption._tag === "Some") {
|
|
31
|
-
const defect = defectOption.value;
|
|
32
|
-
if (defect instanceof Error) {
|
|
33
|
-
throw new RpcDefectError(defect.message, defect);
|
|
22
|
+
return Effect.try({
|
|
23
|
+
try: () => S.decodeUnknownSync(exitSchemaFor(method))(raw),
|
|
24
|
+
catch: (cause) => rpcDefect("legacy_decode_failed", `RPC ${method.name} legacy response decoding failed: ${formatUnknown(cause)}`, cause),
|
|
25
|
+
}).pipe(Effect.flatMap((exit) => {
|
|
26
|
+
if (Exit.isSuccess(exit)) {
|
|
27
|
+
return Effect.succeed(exit.value);
|
|
34
28
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const failureOption = Cause.failureOption(exit.cause);
|
|
30
|
+
if (failureOption._tag === "Some") {
|
|
31
|
+
return Effect.fail(failureOption.value);
|
|
32
|
+
}
|
|
33
|
+
const defectOption = Cause.dieOption(exit.cause);
|
|
34
|
+
if (defectOption._tag === "Some") {
|
|
35
|
+
const defect = defectOption.value;
|
|
36
|
+
const message = defect instanceof Error ? defect.message : String(defect);
|
|
37
|
+
return Effect.fail(rpcDefect("remote_defect", message, defect));
|
|
38
|
+
}
|
|
39
|
+
return Effect.fail(rpcDefect("remote_defect", "RPC call was interrupted or failed unexpectedly", exit.cause));
|
|
40
|
+
}));
|
|
38
41
|
}
|
|
39
42
|
export function createRpcClient(contract, options) {
|
|
40
43
|
const invoke = requireInvoke(options);
|
|
41
44
|
const diagnostics = options?.diagnostics;
|
|
42
45
|
const decodeMode = options?.rpcDecodeMode ?? "envelope";
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
safelyCall(diagnostics?.onDecodeFailure, {
|
|
50
|
-
scope: "rpc-request",
|
|
51
|
-
name: method.name,
|
|
52
|
-
payload: input,
|
|
53
|
-
cause,
|
|
54
|
-
});
|
|
55
|
-
throw new Error(`RPC ${method.name} request encoding failed: ${formatUnknown(cause)}`);
|
|
56
|
-
}
|
|
57
|
-
const raw = await invoke(method.name, encoded);
|
|
58
|
-
const envelope = parseRpcResponseEnvelope(raw);
|
|
59
|
-
if (envelope) {
|
|
60
|
-
switch (envelope.type) {
|
|
61
|
-
case "success":
|
|
62
|
-
try {
|
|
63
|
-
return S.decodeUnknownSync(method.res)(envelope.data);
|
|
64
|
-
}
|
|
65
|
-
catch (cause) {
|
|
46
|
+
const decodeEnvelope = (method, envelope) => {
|
|
47
|
+
switch (envelope.type) {
|
|
48
|
+
case "success":
|
|
49
|
+
return Effect.try({
|
|
50
|
+
try: () => S.decodeUnknownSync(method.res)(envelope.data),
|
|
51
|
+
catch: (cause) => {
|
|
66
52
|
safelyCall(diagnostics?.onDecodeFailure, {
|
|
67
53
|
scope: "rpc-response",
|
|
68
54
|
name: method.name,
|
|
69
55
|
payload: envelope.data,
|
|
70
56
|
cause,
|
|
71
57
|
});
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
catch (cause) {
|
|
58
|
+
return rpcDefect("success_payload_decoding_failed", `RPC ${method.name} success payload decoding failed: ${formatUnknown(cause)}`, cause);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
case "failure":
|
|
62
|
+
if (isNoErrorSchema(method.err)) {
|
|
63
|
+
return Effect.fail(rpcDefect("noerror_contract_violation", `RPC ${method.name} received a failure for a method that declares NoError`, envelope.error));
|
|
64
|
+
}
|
|
65
|
+
const errorSchema = method.err;
|
|
66
|
+
return Effect.try({
|
|
67
|
+
try: () => S.decodeUnknownSync(errorSchema)(envelope.error.data),
|
|
68
|
+
catch: (cause) => {
|
|
83
69
|
safelyCall(diagnostics?.onDecodeFailure, {
|
|
84
70
|
scope: "rpc-response",
|
|
85
71
|
name: method.name,
|
|
86
72
|
payload: envelope.error,
|
|
87
73
|
cause,
|
|
88
74
|
});
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
75
|
+
return rpcDefect("failure_payload_decoding_failed", `RPC ${method.name} failure payload decoding failed: ${formatUnknown(cause)}`, cause);
|
|
76
|
+
},
|
|
77
|
+
}).pipe(Effect.flatMap((decodedError) => Effect.fail(decodedError)));
|
|
78
|
+
case "defect":
|
|
79
|
+
return Effect.fail(rpcDefect("remote_defect", envelope.message, envelope.cause));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const call = (method, input) => Effect.try({
|
|
83
|
+
try: () => S.encodeSync(method.req)(input),
|
|
84
|
+
catch: (cause) => {
|
|
85
|
+
safelyCall(diagnostics?.onDecodeFailure, {
|
|
86
|
+
scope: "rpc-request",
|
|
87
|
+
name: method.name,
|
|
88
|
+
payload: input,
|
|
89
|
+
cause,
|
|
90
|
+
});
|
|
91
|
+
return rpcDefect("request_encoding_failed", `RPC ${method.name} request encoding failed: ${formatUnknown(cause)}`, cause);
|
|
92
|
+
},
|
|
93
|
+
}).pipe(Effect.flatMap((encoded) => Effect.tryPromise({
|
|
94
|
+
try: () => invoke(method.name, encoded),
|
|
95
|
+
catch: (cause) => {
|
|
96
|
+
safelyCall(diagnostics?.onProtocolError, {
|
|
97
|
+
method: method.name,
|
|
98
|
+
response: undefined,
|
|
99
|
+
cause,
|
|
100
|
+
});
|
|
101
|
+
return rpcDefect("invoke_failed", `RPC ${method.name} invoke failed: ${formatUnknown(cause)}`, cause);
|
|
102
|
+
},
|
|
103
|
+
})), Effect.flatMap((raw) => {
|
|
104
|
+
const envelope = parseRpcResponseEnvelope(raw);
|
|
105
|
+
if (envelope) {
|
|
106
|
+
return decodeEnvelope(method, envelope);
|
|
95
107
|
}
|
|
96
108
|
if (decodeMode === "dual") {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
}
|
|
109
|
+
return decodeLegacyExit(method, raw).pipe(Effect.tapError((cause) => {
|
|
110
|
+
if (cause instanceof RpcDefectError &&
|
|
111
|
+
cause.code === "legacy_decode_failed") {
|
|
112
|
+
return Effect.sync(() => safelyCall(diagnostics?.onProtocolError, {
|
|
113
|
+
method: method.name,
|
|
114
|
+
response: raw,
|
|
115
|
+
cause,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
return Effect.void;
|
|
119
|
+
}));
|
|
108
120
|
}
|
|
109
|
-
const cause =
|
|
121
|
+
const cause = rpcDefect("invalid_response_envelope", `RPC ${method.name} response was not a valid envelope.`, raw);
|
|
110
122
|
safelyCall(diagnostics?.onProtocolError, {
|
|
111
123
|
method: method.name,
|
|
112
124
|
response: raw,
|
|
113
125
|
cause,
|
|
114
126
|
});
|
|
115
|
-
|
|
116
|
-
};
|
|
127
|
+
return Effect.fail(cause);
|
|
128
|
+
}));
|
|
117
129
|
const client = Object.create(null);
|
|
118
130
|
const clientRecord = client;
|
|
119
131
|
for (const method of contract.methods) {
|
|
120
|
-
const caller = (
|
|
121
|
-
const payload =
|
|
132
|
+
const caller = (...args) => {
|
|
133
|
+
const payload = args.length === 0
|
|
134
|
+
? {}
|
|
135
|
+
: args[0];
|
|
122
136
|
return call(method, payload);
|
|
123
137
|
};
|
|
124
138
|
clientRecord[method.name] = caller;
|
|
@@ -187,10 +201,19 @@ export function createEventSubscriber(contract, options) {
|
|
|
187
201
|
return registerUnsubscribe(unsubscribe);
|
|
188
202
|
};
|
|
189
203
|
function dispose() {
|
|
204
|
+
let firstError;
|
|
190
205
|
for (const unsubscribe of subscriptions) {
|
|
191
|
-
|
|
206
|
+
try {
|
|
207
|
+
unsubscribe();
|
|
208
|
+
}
|
|
209
|
+
catch (cause) {
|
|
210
|
+
firstError ??= cause;
|
|
211
|
+
}
|
|
192
212
|
}
|
|
193
213
|
subscriptions.clear();
|
|
214
|
+
if (firstError !== undefined) {
|
|
215
|
+
throw firstError;
|
|
216
|
+
}
|
|
194
217
|
}
|
|
195
218
|
return {
|
|
196
219
|
subscribe: subscribeEvent,
|
package/dist/types.d.ts
CHANGED
|
@@ -5,16 +5,19 @@ export type { AnyEvent, AnyMethod, ErrorSchema, ExtractMethod, RpcContract, RpcE
|
|
|
5
5
|
export type Implementations<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>, R = never> = {
|
|
6
6
|
readonly [Name in C["methods"][number]["name"]]: (input: RpcInput<ExtractMethod<C["methods"], Name>>) => Effect.Effect<RpcOutput<ExtractMethod<C["methods"], Name>>, RpcError<ExtractMethod<C["methods"], Name>>, R>;
|
|
7
7
|
};
|
|
8
|
-
type IsEmptyObject<T> = keyof T extends never ? true : false;
|
|
9
|
-
export type
|
|
10
|
-
export type RpcClient<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
|
|
11
|
-
readonly [Name in C["methods"][number]["name"]]: RpcCaller<ExtractMethod<C["methods"], Name>>;
|
|
12
|
-
};
|
|
8
|
+
type IsEmptyObject<T> = T extends object ? keyof T extends never ? true : false : false;
|
|
9
|
+
export type RpcDefectCode = "request_encoding_failed" | "invoke_failed" | "success_payload_decoding_failed" | "failure_payload_decoding_failed" | "noerror_contract_violation" | "invalid_response_envelope" | "legacy_decode_failed" | "remote_defect";
|
|
13
10
|
export declare class RpcDefectError extends Error {
|
|
11
|
+
readonly code: RpcDefectCode;
|
|
14
12
|
readonly cause: unknown;
|
|
15
13
|
readonly _tag = "RpcDefectError";
|
|
16
|
-
constructor(message: string, cause: unknown);
|
|
14
|
+
constructor(code: RpcDefectCode, message: string, cause: unknown);
|
|
17
15
|
}
|
|
16
|
+
export type RpcMethodError<M extends AnyMethod> = RpcError<M> | RpcDefectError;
|
|
17
|
+
export type RpcCaller<M extends AnyMethod> = IsEmptyObject<RpcInput<M>> extends true ? () => Effect.Effect<RpcOutput<M>, RpcMethodError<M>> : (input: RpcInput<M>) => Effect.Effect<RpcOutput<M>, RpcMethodError<M>>;
|
|
18
|
+
export type RpcClient<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
|
|
19
|
+
readonly [Name in C["methods"][number]["name"]]: RpcCaller<ExtractMethod<C["methods"], Name>>;
|
|
20
|
+
};
|
|
18
21
|
export type ChannelPrefix = {
|
|
19
22
|
readonly rpc: string;
|
|
20
23
|
readonly event: string;
|
|
@@ -37,7 +40,7 @@ export type DispatchFailureContext = {
|
|
|
37
40
|
readonly payload: unknown;
|
|
38
41
|
readonly cause: unknown;
|
|
39
42
|
};
|
|
40
|
-
export type DroppedEventReason = "queue_full" | "encoding_failed";
|
|
43
|
+
export type DroppedEventReason = "queue_full" | "encoding_failed" | "window_unavailable" | "dispatch_failed";
|
|
41
44
|
export type DroppedEventContext = {
|
|
42
45
|
readonly event: string;
|
|
43
46
|
readonly payload: unknown;
|
|
@@ -52,7 +55,7 @@ export type RpcClientDiagnostics = {
|
|
|
52
55
|
readonly onProtocolError?: (context: ProtocolErrorContext) => void;
|
|
53
56
|
};
|
|
54
57
|
export type RpcClientOptions = {
|
|
55
|
-
readonly invoke
|
|
58
|
+
readonly invoke: RpcInvoke;
|
|
56
59
|
readonly diagnostics?: RpcClientDiagnostics;
|
|
57
60
|
readonly rpcDecodeMode?: RpcResponseDecodeMode;
|
|
58
61
|
};
|
|
@@ -112,7 +115,7 @@ export type EventSubscriberDiagnostics = {
|
|
|
112
115
|
readonly onDecodeFailure?: (context: DecodeFailureContext) => void;
|
|
113
116
|
};
|
|
114
117
|
export type EventSubscriberOptions = {
|
|
115
|
-
readonly subscribe
|
|
118
|
+
readonly subscribe: EventSubscribe;
|
|
116
119
|
readonly decodeMode?: EventDecodeMode;
|
|
117
120
|
readonly diagnostics?: EventSubscriberDiagnostics;
|
|
118
121
|
};
|
|
@@ -121,4 +124,5 @@ export interface EventSubscriber<C extends RpcContract<readonly AnyMethod[], rea
|
|
|
121
124
|
readonly subscribeByName: (name: string, handler: (payload: unknown) => void) => () => void;
|
|
122
125
|
readonly dispose: () => void;
|
|
123
126
|
}
|
|
127
|
+
export type { IpcBridge, IpcBridgeGlobal, IpcKit, IpcKitOptions, IpcMainHandle, } from "./kit.ts";
|
|
124
128
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EAET,aAAa,EACb,WAAW,EACX,QAAQ,EAER,eAAe,EACf,QAAQ,EAER,SAAS,EAEV,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,QAAQ,EACR,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,SAAS,EACT,SAAS,EACT,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,WAAW,CAAC,SAAS,SAAS,EAAE,EAAE,SAAS,QAAQ,EAAE,CAAC,EAChE,CAAC,GAAG,KAAK,IACP;IACF,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAC/C,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,KAC/C,MAAM,CAAC,MAAM,CAChB,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,EAC5C,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,EAC3C,CAAC,CACF;CACF,CAAC;AAEF,KAAK,aAAa,CAAC,CAAC,IAAI,MAAM,CAAC,SAAS,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-effect-rpc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Typed IPC RPC for Electron, built on Effect and @effect/schema",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
7
11
|
"./main": {
|
|
8
12
|
"types": "./dist/main.d.ts",
|
|
9
13
|
"default": "./dist/main.js"
|
|
@@ -35,6 +39,12 @@
|
|
|
35
39
|
"scripts": {
|
|
36
40
|
"build": "tsc",
|
|
37
41
|
"prepublishOnly": "bun run build",
|
|
42
|
+
"test:unit": "bun test",
|
|
43
|
+
"test:types": "bun run typecheck && bunx tsc -p tsconfig.type-tests.json --noEmit",
|
|
44
|
+
"test:packaging": "bash ./scripts/run-packaging-checks.sh",
|
|
45
|
+
"test:integration": "bun test __tests__/integration.test.ts",
|
|
46
|
+
"test:stress": "bun test __tests__/stress.test.ts",
|
|
47
|
+
"test:full": "bun run test:unit && bun run test:types && bun run test:packaging && bun run test:integration && bun run test:stress",
|
|
38
48
|
"test": "bun test",
|
|
39
49
|
"typecheck": "tsc --noEmit"
|
|
40
50
|
},
|