electron-effect-rpc 0.8.0 → 0.9.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/CHANGELOG.md +82 -0
- package/README.md +69 -45
- package/dist/contract.d.ts +5 -7
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +6 -4
- package/dist/kit.d.ts +20 -2
- package/dist/kit.d.ts.map +1 -1
- package/dist/kit.js +6 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +55 -20
- package/dist/preload-bridge.d.ts.map +1 -1
- package/dist/preload-bridge.js +4 -2
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +23 -5
- package/dist/types.d.ts +41 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/package.json +9 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- Schemas now come from `effect/Schema` (Effect core) instead of the deprecated
|
|
8
|
+
`@effect/schema` package. The `@effect/schema` peer dependency was removed and
|
|
9
|
+
the `effect` peer floor raised to `>=3.10.0`. Update contract imports:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// before
|
|
13
|
+
import * as S from "@effect/schema/Schema";
|
|
14
|
+
// after
|
|
15
|
+
import * as S from "effect/Schema";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `event()` no longer accepts a third `context` schema argument. It was never
|
|
19
|
+
read by the publisher or subscriber; remove it from any `event(...)` calls.
|
|
20
|
+
- `channelPrefix.rpc` and `channelPrefix.event` must now differ; identical
|
|
21
|
+
prefixes throw at construction time.
|
|
22
|
+
- Providing `streamHandlers` when the contract defines no `streamMethods` now
|
|
23
|
+
throws instead of being silently ignored.
|
|
24
|
+
- Methods whose request schema type is `object` (e.g. `S.Object`) now require
|
|
25
|
+
an argument at the call site; previously the client generated a zero-arg
|
|
26
|
+
caller that always sent `{}`.
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Handlers (unary and stream) receive an optional second `context` argument:
|
|
31
|
+
`{ sender: WebContentsLike | null }`.
|
|
32
|
+
- `EventSubscriber.stream(event)` — Effect-native event consumption as a
|
|
33
|
+
`Stream` that unsubscribes when its scope closes.
|
|
34
|
+
- `ipc.renderer(bridge, { diagnostics })` — renderer-side diagnostics hooks for
|
|
35
|
+
RPC, events, and streams in kit mode.
|
|
36
|
+
- `assertValidChannelPrefix` exported from `electron-effect-rpc/types`.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Main-side stream fibers no longer leak when the renderer goes away without
|
|
41
|
+
cancelling: a destroyed sender now terminates the pipeline on the next chunk,
|
|
42
|
+
and when the real Electron `WebContents` emitter is available the fiber is
|
|
43
|
+
interrupted immediately on `destroyed`.
|
|
44
|
+
- Normally-completed streams no longer send a redundant `stream-cancel` invoke.
|
|
45
|
+
- `isNoErrorSchema` now matches `Never` schemas by AST tag, so a duplicated
|
|
46
|
+
schema package instance can't silently turn typed failures into defects.
|
|
47
|
+
- Stream failure-encoding defects now carry the encoding error message instead
|
|
48
|
+
of `[object Object]`.
|
|
49
|
+
|
|
50
|
+
## 0.8.0 and earlier
|
|
51
|
+
|
|
52
|
+
`getWindow` was renamed to `getWindows` and now returns an array, enabling
|
|
53
|
+
multi-window event fan-out. Empty array replaces `null` for "no windows."
|
|
54
|
+
|
|
55
|
+
Before:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
getWindow: () => mainWindow,
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
After:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
getWindows: () => [mainWindow],
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Renderer RPC methods now return `Effect.Effect` instead of `Promise`, and
|
|
68
|
+
`IpcMainHandle.emit` was removed in favor of `publish`.
|
|
69
|
+
|
|
70
|
+
Before:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const result = await client.GetAppVersion();
|
|
74
|
+
await mainRpc.emit(WorkUnitProgress, payload);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
After:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
const result = await Effect.runPromise(client.GetAppVersion());
|
|
81
|
+
await Effect.runPromise(mainRpc.publish(WorkUnitProgress, payload));
|
|
82
|
+
```
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# electron-effect-rpc
|
|
2
2
|
|
|
3
|
-
Typed IPC RPC for Electron, built on Effect and
|
|
3
|
+
Typed IPC RPC for Electron, built on Effect and `effect/Schema`.
|
|
4
4
|
|
|
5
5
|
The ergonomic default is now a single shared `createIpcKit` configuration that
|
|
6
6
|
you reuse in main, preload, and renderer code. Low-level subpath APIs still
|
|
@@ -24,12 +24,12 @@ ESM-capable build pipeline.
|
|
|
24
24
|
|
|
25
25
|
- Electron with context isolation enabled.
|
|
26
26
|
- ESM-capable bundling.
|
|
27
|
-
- Peer dependencies: `effect
|
|
27
|
+
- Peer dependencies: `effect` (>=3.10), `electron`.
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
|
-
bun add electron-effect-rpc effect
|
|
32
|
+
bun add electron-effect-rpc effect
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
## Quickstart (Kit-First)
|
|
@@ -37,7 +37,7 @@ bun add electron-effect-rpc effect @effect/schema
|
|
|
37
37
|
### 1) Define contract and kit once
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
import * as S from "
|
|
40
|
+
import * as S from "effect/Schema";
|
|
41
41
|
import { createIpcKit, defineContract, event, rpc, streamRpc } from "electron-effect-rpc";
|
|
42
42
|
|
|
43
43
|
export const GetAppVersion = rpc("GetAppVersion", S.Struct({}), S.Struct({ version: S.String }));
|
|
@@ -74,15 +74,22 @@ export const ipc = createIpcKit({
|
|
|
74
74
|
### 2) Main process
|
|
75
75
|
|
|
76
76
|
```ts
|
|
77
|
-
import
|
|
77
|
+
import path from "node:path";
|
|
78
|
+
import { app, BrowserWindow, ipcMain } from "electron";
|
|
78
79
|
import { Effect, Stream } from "effect";
|
|
79
80
|
import * as Runtime from "effect/Runtime";
|
|
80
81
|
import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
|
|
81
82
|
|
|
83
|
+
const mainWindow = new BrowserWindow({
|
|
84
|
+
webPreferences: { preload: path.join(import.meta.dirname, "preload.js") },
|
|
85
|
+
});
|
|
86
|
+
|
|
82
87
|
const mainRpc = ipc.main({
|
|
83
88
|
ipcMain,
|
|
84
89
|
handlers: {
|
|
85
90
|
GetAppVersion: () => Effect.succeed({ version: app.getVersion() }),
|
|
91
|
+
// Handlers may take an optional second argument with request context:
|
|
92
|
+
// GetAppVersion: (_input, { sender }) => ...
|
|
86
93
|
},
|
|
87
94
|
streamHandlers: {
|
|
88
95
|
StreamAiGeneration: ({ prompt }) =>
|
|
@@ -145,25 +152,44 @@ const unsubscribe = events.subscribe(WorkUnitProgress, (payload) => {
|
|
|
145
152
|
console.log(payload.chunk);
|
|
146
153
|
});
|
|
147
154
|
|
|
155
|
+
// Or consume events as an Effect Stream (unsubscribes when the scope closes):
|
|
156
|
+
await Effect.runPromise(
|
|
157
|
+
events
|
|
158
|
+
.stream(WorkUnitProgress)
|
|
159
|
+
.pipe(Stream.runForEach((payload) => Effect.sync(() => console.log(payload.chunk)))),
|
|
160
|
+
);
|
|
161
|
+
|
|
148
162
|
// later
|
|
149
163
|
unsubscribe();
|
|
150
164
|
dispose();
|
|
151
165
|
```
|
|
152
166
|
|
|
167
|
+
Renderer-side diagnostics hooks are available through the second argument:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const renderer = ipc.renderer(window.api, {
|
|
171
|
+
diagnostics: {
|
|
172
|
+
rpc: { onDecodeFailure: (ctx) => console.warn("rpc decode failure", ctx) },
|
|
173
|
+
events: { onDecodeFailure: (ctx) => console.warn("event decode failure", ctx) },
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
153
178
|
### 5) Window typing
|
|
154
179
|
|
|
180
|
+
Use the exported `IpcBridgeGlobal` helper so the declared shape stays in sync
|
|
181
|
+
with what `ipc.preload()` exposes:
|
|
182
|
+
|
|
155
183
|
```ts
|
|
184
|
+
import type { IpcBridgeGlobal } from "electron-effect-rpc";
|
|
185
|
+
|
|
156
186
|
declare global {
|
|
157
|
-
interface Window {
|
|
158
|
-
api: {
|
|
159
|
-
invoke: (method: string, payload: unknown) => Promise<unknown>;
|
|
160
|
-
subscribe: (name: string, handler: (payload: unknown) => void) => () => void;
|
|
161
|
-
onStreamFrame?: (listener: (frame: unknown) => void) => () => void;
|
|
162
|
-
};
|
|
163
|
-
}
|
|
187
|
+
interface Window extends IpcBridgeGlobal {}
|
|
164
188
|
}
|
|
165
189
|
```
|
|
166
190
|
|
|
191
|
+
For a custom global name, use `IpcBridgeGlobal<"myBridge">`.
|
|
192
|
+
|
|
167
193
|
## Error Model
|
|
168
194
|
|
|
169
195
|
Domain failures are modeled with tagged error schemas and are surfaced in the
|
|
@@ -177,39 +203,37 @@ which includes a stable `code` discriminator:
|
|
|
177
203
|
`stream_invoke_failed`, `stream_handshake_invalid`,
|
|
178
204
|
`stream_chunk_decode_failed`, and `stream_error_decode_failed`.
|
|
179
205
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
`
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
await Effect.runPromise(mainRpc.publish(WorkUnitProgress, payload));
|
|
212
|
-
```
|
|
206
|
+
Defect envelopes carry the main-process error message verbatim across IPC. If
|
|
207
|
+
any window in your app loads remote or less-trusted content, treat that as
|
|
208
|
+
information disclosure: catch and sanitize errors in your handlers rather than
|
|
209
|
+
letting raw exceptions (paths, query fragments) become defects.
|
|
210
|
+
|
|
211
|
+
## Operational Notes
|
|
212
|
+
|
|
213
|
+
**Stream backpressure.** Stream frames are pushed from main as fast as the
|
|
214
|
+
handler produces them; there is no acknowledgment across the IPC boundary. The
|
|
215
|
+
renderer buffers with `bufferSize: "unbounded"` by default, which is lossless
|
|
216
|
+
but means a fast producer with a slow consumer grows renderer memory. Bounded
|
|
217
|
+
buffers (`dropping`/`sliding`) are lossy by design and, with current Effect
|
|
218
|
+
`Stream.asyncPush` internals, can lose terminal signals under sustained
|
|
219
|
+
pressure. Rate-limit fast producers in the handler (`Stream.throttle`,
|
|
220
|
+
batching) rather than relying on a bounded renderer buffer.
|
|
221
|
+
|
|
222
|
+
**Unary RPC cancellation.** Interrupting the renderer-side Effect of a
|
|
223
|
+
client call (e.g. via `Effect.timeout`) does not abort the main-side handler;
|
|
224
|
+
the underlying `ipcRenderer.invoke` is not abortable. The handler runs to
|
|
225
|
+
completion and its response is discarded. Streaming RPC does propagate
|
|
226
|
+
cancellation to main. If a unary handler does expensive work, model it as a
|
|
227
|
+
stream or build explicit cancellation into your contract.
|
|
228
|
+
|
|
229
|
+
**Renderer teardown.** Main interrupts a stream's fiber when the renderer's
|
|
230
|
+
`webContents` is destroyed (immediately when the real Electron `WebContents`
|
|
231
|
+
event emitter is available, otherwise on the next chunk), so handler fibers do
|
|
232
|
+
not outlive closed windows.
|
|
233
|
+
|
|
234
|
+
## Migration Notes
|
|
235
|
+
|
|
236
|
+
See [CHANGELOG.md](./CHANGELOG.md) for breaking changes between versions.
|
|
213
237
|
|
|
214
238
|
## Low-Level APIs (Still Supported)
|
|
215
239
|
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as S from "
|
|
1
|
+
import * as S from "effect/Schema";
|
|
2
2
|
export type SchemaNoContext = S.Schema.AnyNoContext;
|
|
3
3
|
export declare const NoError: typeof S.Never;
|
|
4
4
|
export type NoError = typeof NoError;
|
|
@@ -12,14 +12,12 @@ export interface RpcMethod<Name extends string, Req extends SchemaNoContext, Res
|
|
|
12
12
|
}
|
|
13
13
|
export declare function rpc<const Name extends string, Req extends SchemaNoContext, Res extends SchemaNoContext, Err extends ErrorSchema>(name: Name, req: Req, res: Res, err: Err): RpcMethod<Name, Req, Res, Err>;
|
|
14
14
|
export declare function rpc<const Name extends string, Req extends SchemaNoContext, Res extends SchemaNoContext>(name: Name, req: Req, res: Res): RpcMethod<Name, Req, Res, NoError>;
|
|
15
|
-
export interface RpcEvent<Payload extends SchemaNoContext,
|
|
15
|
+
export interface RpcEvent<Payload extends SchemaNoContext, Name extends string = string> {
|
|
16
16
|
readonly name: Name;
|
|
17
17
|
readonly payload: Payload;
|
|
18
|
-
readonly context: Context;
|
|
19
18
|
}
|
|
20
|
-
export declare function event<const Name extends string, Payload extends SchemaNoContext
|
|
21
|
-
export declare
|
|
22
|
-
export declare const exitSchemaFor: <Name extends string, Req extends SchemaNoContext, Res extends SchemaNoContext, Err extends ErrorSchema>(method: RpcMethod<Name, Req, Res, Err>) => S.Exit<Res, Err, S.Defect>;
|
|
19
|
+
export declare function event<const Name extends string, Payload extends SchemaNoContext>(name: Name, payload: Payload): RpcEvent<Payload, Name>;
|
|
20
|
+
export declare const exitSchemaFor: <Name extends string, Req extends SchemaNoContext, Res extends SchemaNoContext, Err extends ErrorSchema>(method: RpcMethod<Name, Req, Res, Err>) => S.Exit<Res, Err, typeof S.Defect>;
|
|
23
21
|
export interface StreamRpcMethod<Name extends string, Req extends SchemaNoContext, Chunk extends SchemaNoContext, Err extends ErrorSchema = NoError> {
|
|
24
22
|
readonly _tag: "StreamRpcMethod";
|
|
25
23
|
readonly name: Name;
|
|
@@ -37,7 +35,7 @@ export type ExtractStreamMethod<Methods extends readonly AnyStreamMethod[], Name
|
|
|
37
35
|
readonly name: Name;
|
|
38
36
|
}>;
|
|
39
37
|
export type AnyMethod = RpcMethod<string, SchemaNoContext, SchemaNoContext, ErrorSchema>;
|
|
40
|
-
export type AnyEvent = RpcEvent<SchemaNoContext,
|
|
38
|
+
export type AnyEvent = RpcEvent<SchemaNoContext, string>;
|
|
41
39
|
export type RpcInput<M extends AnyMethod> = S.Schema.Type<M["req"]>;
|
|
42
40
|
export type RpcOutput<M extends AnyMethod> = S.Schema.Type<M["res"]>;
|
|
43
41
|
export type RpcError<M extends AnyMethod> = S.Schema.Type<M["err"]>;
|
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import * as S from "
|
|
1
|
+
import * as S from "effect/Schema";
|
|
2
2
|
export const NoError = S.Never;
|
|
3
3
|
export function isNoErrorSchema(schema) {
|
|
4
|
-
|
|
4
|
+
// Also match by AST tag so a Never schema from a second copy of the
|
|
5
|
+
// schema package (npm dedup failure) is still treated as NoError.
|
|
6
|
+
return schema === NoError || schema.ast._tag === "NeverKeyword";
|
|
5
7
|
}
|
|
6
8
|
export function rpc(name, req, res, err = NoError) {
|
|
7
9
|
return { name, req, res, err };
|
|
8
10
|
}
|
|
9
|
-
export function event(name, payload
|
|
10
|
-
return { name, payload
|
|
11
|
+
export function event(name, payload) {
|
|
12
|
+
return { name, payload };
|
|
11
13
|
}
|
|
12
14
|
export const exitSchemaFor = (method) => S.Exit({
|
|
13
15
|
success: method.res,
|
package/dist/kit.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import type * as Runtime from "effect/Runtime";
|
|
3
3
|
import type { AnyEvent, AnyMethod, AnyStreamMethod, RpcContract, RpcEventPayload } from "./contract.ts";
|
|
4
|
-
import { type ChannelPrefix, type EventDecodeMode, type EventPublisherDiagnostics, type EventSubscribe, type EventSubscriber, type IpcMainLike, type Implementations, type OnStreamFrame, type RendererWindowLike, type RpcClient, type RpcEndpoint, type RpcEndpointDiagnostics, type RpcEventPublisher, type RpcInvoke, type RpcResponseDecodeMode, type StreamImplementations, type StreamRpcClient, type StreamBufferOptions } from "./types.ts";
|
|
4
|
+
import { type ChannelPrefix, type EventDecodeMode, type EventPublisherDiagnostics, type EventSubscribe, type EventSubscriber, type EventSubscriberDiagnostics, type IpcMainLike, type Implementations, type OnStreamFrame, type RendererWindowLike, type RpcClient, type RpcClientDiagnostics, type RpcEndpoint, type RpcEndpointDiagnostics, type RpcEventPublisher, type RpcInvoke, type RpcResponseDecodeMode, type StreamImplementations, type StreamRpcClient, type StreamBufferOptions } from "./types.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Narrow surface the preload script exposes to the renderer.
|
|
7
|
+
*
|
|
8
|
+
* Implementations are responsible for applying the kit's channel prefixes:
|
|
9
|
+
* `invoke(method, payload)` must call `ipcRenderer.invoke(channelPrefix.rpc +
|
|
10
|
+
* method, payload)`, `subscribe(name, ...)` must listen on
|
|
11
|
+
* `channelPrefix.event + name`, and `onStreamFrame` must listen on
|
|
12
|
+
* `channelPrefix.rpc + "sf"`. The bridge produced by `ipc.preload()` does this
|
|
13
|
+
* for you; hand-written bridges that skip the prefixes fail with
|
|
14
|
+
* `invoke_failed` defects at runtime.
|
|
15
|
+
*/
|
|
5
16
|
export type IpcBridge = {
|
|
6
17
|
readonly invoke: RpcInvoke;
|
|
7
18
|
readonly subscribe: EventSubscribe;
|
|
@@ -38,6 +49,13 @@ type IpcPreloadOptions = {
|
|
|
38
49
|
readonly global?: string;
|
|
39
50
|
readonly electronModule?: unknown;
|
|
40
51
|
};
|
|
52
|
+
type IpcRendererOptions = {
|
|
53
|
+
readonly diagnostics?: {
|
|
54
|
+
readonly rpc?: RpcClientDiagnostics;
|
|
55
|
+
readonly events?: EventSubscriberDiagnostics;
|
|
56
|
+
readonly stream?: RpcClientDiagnostics;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
41
59
|
export type IpcMainHandle<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> = {
|
|
42
60
|
readonly endpoint: RpcEndpoint;
|
|
43
61
|
readonly publisher: RpcEventPublisher<C>;
|
|
@@ -66,7 +84,7 @@ export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent
|
|
|
66
84
|
readonly bridge: IpcBridge;
|
|
67
85
|
readonly expose: () => void;
|
|
68
86
|
};
|
|
69
|
-
readonly renderer: (bridge: IpcBridge) => {
|
|
87
|
+
readonly renderer: (bridge: IpcBridge, options?: IpcRendererOptions) => {
|
|
70
88
|
readonly client: RpcClient<C>;
|
|
71
89
|
readonly events: EventSubscriber<C>;
|
|
72
90
|
readonly streamClient: StreamRpcClient<C>;
|
package/dist/kit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,WAAW,EACX,eAAe,EAChB,MAAM,eAAe,CAAC;AAQvB,OAAO,
|
|
1
|
+
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
|
package/dist/kit.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { createEventPublisher, createRpcEndpoint } from "./main.js";
|
|
3
3
|
import { createBridgeAdaptersFromBindings, exposeIpcBridgeFromBindings, resolveElectronRendererBindings, } from "./preload-bridge.js";
|
|
4
4
|
import { createEventSubscriber, createRpcClient, createStreamRpcClient } from "./renderer.js";
|
|
5
|
-
import { defaultChannelPrefix, } from "./types.js";
|
|
5
|
+
import { assertValidChannelPrefix, defaultChannelPrefix, } from "./types.js";
|
|
6
6
|
function loadElectronModule(electronModule) {
|
|
7
7
|
if (electronModule !== undefined) {
|
|
8
8
|
return electronModule;
|
|
@@ -27,7 +27,7 @@ export function createIpcKit(options) {
|
|
|
27
27
|
};
|
|
28
28
|
const contract = options.contract;
|
|
29
29
|
const channelPrefix = options.channelPrefix
|
|
30
|
-
? { ...options.channelPrefix }
|
|
30
|
+
? assertValidChannelPrefix({ ...options.channelPrefix })
|
|
31
31
|
: { ...defaultChannelPrefix };
|
|
32
32
|
const bridgeGlobal = options.bridge?.global ?? "api";
|
|
33
33
|
const rpcDecodeMode = options.decode?.rpc ?? "envelope";
|
|
@@ -131,7 +131,7 @@ export function createIpcKit(options) {
|
|
|
131
131
|
},
|
|
132
132
|
};
|
|
133
133
|
};
|
|
134
|
-
const renderer = (bridge) => {
|
|
134
|
+
const renderer = (bridge, rendererOptions) => {
|
|
135
135
|
const hasStreamMethods = (contract.streamMethods?.length ?? 0) > 0;
|
|
136
136
|
if (hasStreamMethods && !bridge.onStreamFrame) {
|
|
137
137
|
throw new Error("Contract defines stream methods but bridge.onStreamFrame is missing. " +
|
|
@@ -143,6 +143,7 @@ export function createIpcKit(options) {
|
|
|
143
143
|
invoke: bridge.invoke,
|
|
144
144
|
onStreamFrame: bridge.onStreamFrame,
|
|
145
145
|
streamBuffer,
|
|
146
|
+
diagnostics: rendererOptions?.diagnostics?.stream,
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
const emptyStreamClient = Object.create(null);
|
|
@@ -150,10 +151,12 @@ export function createIpcKit(options) {
|
|
|
150
151
|
client: createRpcClient(contract, {
|
|
151
152
|
invoke: bridge.invoke,
|
|
152
153
|
rpcDecodeMode,
|
|
154
|
+
diagnostics: rendererOptions?.diagnostics?.rpc,
|
|
153
155
|
}),
|
|
154
156
|
events: createEventSubscriber(contract, {
|
|
155
157
|
subscribe: bridge.subscribe,
|
|
156
158
|
decodeMode: eventDecodeMode,
|
|
159
|
+
diagnostics: rendererOptions?.diagnostics?.events,
|
|
157
160
|
}),
|
|
158
161
|
streamClient: streamHandle?.client ?? emptyStreamClient,
|
|
159
162
|
dispose: () => {
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EAQZ,MAAM,eAAe,CAAC;AAcvB,OAAO,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EAQZ,MAAM,eAAe,CAAC;AAcvB,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAIvB,MAAM,YAAY,CAAC;AAwCpB,wBAAgB,iBAAiB,CAC/B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EACxE,CAAC,GAAG,KAAK,EAET,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,EAChF,OAAO,EAAE,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,GAC1E,WAAW,CAmeb;AAmBD,wBAAgB,oBAAoB,CAClC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACtD,OAAO,EAAE,qBAAqB,GAC7B,iBAAiB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAmNhE"}
|
package/dist/main.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import * as S from "
|
|
1
|
+
import * as S from "effect/Schema";
|
|
2
2
|
import { Cause, Effect, Exit, FiberId, Stream } from "effect";
|
|
3
3
|
import * as Runtime from "effect/Runtime";
|
|
4
4
|
import { isNoErrorSchema } from "./contract.js";
|
|
5
5
|
import { extractErrorTag, formatUnknown, isRecord, safelyCall, toDefectEnvelope, } from "./protocol.js";
|
|
6
|
-
import { defaultChannelPrefix, } from "./types.js";
|
|
6
|
+
import { assertValidChannelPrefix, defaultChannelPrefix, } from "./types.js";
|
|
7
7
|
function resolveChannelPrefix(prefix) {
|
|
8
|
-
return prefix
|
|
8
|
+
return prefix ? assertValidChannelPrefix(prefix) : defaultChannelPrefix;
|
|
9
9
|
}
|
|
10
10
|
function isWebContentsLike(value) {
|
|
11
11
|
if (!isRecord(value))
|
|
@@ -53,7 +53,7 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
53
53
|
const encodeSuccess = S.encodeSync(method.res);
|
|
54
54
|
const encodeFailure = isNoErrorSchema(method.err) ? null : S.encodeSync(method.err);
|
|
55
55
|
const channel = `${channelPrefix.rpc}${method.name}`;
|
|
56
|
-
listeners.set(channel, async function handleRpcRequest(
|
|
56
|
+
listeners.set(channel, async function handleRpcRequest(event, rawPayload) {
|
|
57
57
|
let input;
|
|
58
58
|
try {
|
|
59
59
|
input = decodeInput(rawPayload);
|
|
@@ -69,7 +69,7 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
69
69
|
}
|
|
70
70
|
let effect;
|
|
71
71
|
try {
|
|
72
|
-
effect = impl(input);
|
|
72
|
+
effect = impl(input, { sender: extractSender(event) });
|
|
73
73
|
}
|
|
74
74
|
catch (cause) {
|
|
75
75
|
return toDefectEnvelope(cause, `RPC ${method.name} implementation threw`);
|
|
@@ -121,6 +121,11 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
121
121
|
if (streamMethods.length > 0 && !streamHandlerImpls) {
|
|
122
122
|
throw new Error("Contract defines stream methods but no streamHandlers were provided.");
|
|
123
123
|
}
|
|
124
|
+
if (streamMethods.length === 0 &&
|
|
125
|
+
streamHandlerImpls &&
|
|
126
|
+
Object.keys(streamHandlerImpls).length > 0) {
|
|
127
|
+
throw new Error("streamHandlers were provided but the contract defines no stream methods.");
|
|
128
|
+
}
|
|
124
129
|
if (streamMethods.length > 0 && streamHandlerImpls) {
|
|
125
130
|
const streamMethodNames = new Set(streamMethods.map((m) => m.name));
|
|
126
131
|
for (const name in streamHandlerImpls) {
|
|
@@ -179,7 +184,7 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
179
184
|
}).pipe(Effect.ignore);
|
|
180
185
|
let handlerStream;
|
|
181
186
|
try {
|
|
182
|
-
handlerStream = impl(input);
|
|
187
|
+
handlerStream = impl(input, { sender });
|
|
183
188
|
}
|
|
184
189
|
catch (cause) {
|
|
185
190
|
return toDefectEnvelope(cause, `Stream ${method.name} implementation threw`);
|
|
@@ -198,11 +203,19 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
198
203
|
},
|
|
199
204
|
};
|
|
200
205
|
}
|
|
201
|
-
catch {
|
|
202
|
-
|
|
206
|
+
catch (encodeCause) {
|
|
207
|
+
return {
|
|
208
|
+
type: "defect",
|
|
209
|
+
streamId,
|
|
210
|
+
message: `Stream ${method.name} failure encoding failed: ${formatUnknown(encodeCause)}`,
|
|
211
|
+
};
|
|
203
212
|
}
|
|
204
213
|
}
|
|
205
|
-
return {
|
|
214
|
+
return {
|
|
215
|
+
type: "defect",
|
|
216
|
+
streamId,
|
|
217
|
+
message: `Stream ${method.name} returned a typed failure, but method declares NoError: ${formatUnknown(failure.value)}`,
|
|
218
|
+
};
|
|
206
219
|
}
|
|
207
220
|
if (Cause.isInterruptedOnly(cause)) {
|
|
208
221
|
return { type: "end", streamId };
|
|
@@ -214,23 +227,45 @@ export function createRpcEndpoint(contract, ipc, implementations, options) {
|
|
|
214
227
|
message: defect._tag === "Some" ? formatUnknown(defect.value) : "Stream failed unexpectedly",
|
|
215
228
|
};
|
|
216
229
|
};
|
|
217
|
-
const streamEffect = handlerStream.pipe(Stream.mapEffect((chunk) => Effect.try({
|
|
218
|
-
try: () => {
|
|
219
|
-
if (sender.isDestroyed())
|
|
220
|
-
return;
|
|
221
|
-
sender.send(sfChannel, { type: "data", streamId, payload: encodeChunk(chunk) });
|
|
222
|
-
},
|
|
223
|
-
catch: () => undefined,
|
|
224
|
-
}).pipe(Effect.ignore)), Stream.runDrain, Effect.andThen(() => trySend({ type: "end", streamId })), Effect.catchAllCause((cause) => sender.isDestroyed() ? Effect.void : trySend(buildTerminalFrame(cause))), Effect.ensuring(Effect.sync(() => {
|
|
225
|
-
activeStreams.delete(streamId);
|
|
226
|
-
})));
|
|
227
230
|
// Reserve entry BEFORE forking
|
|
228
231
|
const entry = {
|
|
229
232
|
fiber: null,
|
|
230
233
|
senderId: sender.id,
|
|
231
234
|
};
|
|
235
|
+
const onSenderDestroyed = () => {
|
|
236
|
+
entry.fiber?.unsafeInterruptAsFork(FiberId.none);
|
|
237
|
+
};
|
|
238
|
+
const streamEffect = handlerStream.pipe(Stream.mapEffect((chunk) => Effect.suspend(() => {
|
|
239
|
+
// A destroyed renderer can never consume more chunks:
|
|
240
|
+
// terminate the pipeline instead of draining the source.
|
|
241
|
+
if (sender.isDestroyed()) {
|
|
242
|
+
return Effect.interrupt;
|
|
243
|
+
}
|
|
244
|
+
return Effect.try({
|
|
245
|
+
try: () => sender.send(sfChannel, { type: "data", streamId, payload: encodeChunk(chunk) }),
|
|
246
|
+
catch: () => undefined,
|
|
247
|
+
}).pipe(Effect.ignore);
|
|
248
|
+
})), Stream.runDrain, Effect.andThen(() => trySend({ type: "end", streamId })), Effect.catchAllCause((cause) => sender.isDestroyed() ? Effect.void : trySend(buildTerminalFrame(cause))), Effect.ensuring(Effect.sync(() => {
|
|
249
|
+
activeStreams.delete(streamId);
|
|
250
|
+
if (typeof sender.removeListener === "function") {
|
|
251
|
+
sender.removeListener("destroyed", onSenderDestroyed);
|
|
252
|
+
}
|
|
253
|
+
})));
|
|
232
254
|
activeStreams.set(streamId, entry);
|
|
233
|
-
|
|
255
|
+
if (typeof sender.once === "function") {
|
|
256
|
+
sender.once("destroyed", onSenderDestroyed);
|
|
257
|
+
}
|
|
258
|
+
let fiber;
|
|
259
|
+
try {
|
|
260
|
+
fiber = runFork(streamEffect);
|
|
261
|
+
}
|
|
262
|
+
catch (cause) {
|
|
263
|
+
activeStreams.delete(streamId);
|
|
264
|
+
if (typeof sender.removeListener === "function") {
|
|
265
|
+
sender.removeListener("destroyed", onSenderDestroyed);
|
|
266
|
+
}
|
|
267
|
+
return toDefectEnvelope(cause, `Stream ${method.name} failed to start`);
|
|
268
|
+
}
|
|
234
269
|
entry.fiber = fiber;
|
|
235
270
|
const response = {
|
|
236
271
|
type: "success",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preload-bridge.d.ts","sourceRoot":"","sources":["../src/preload-bridge.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"preload-bridge.d.ts","sourceRoot":"","sources":["../src/preload-bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,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;IACnC,QAAQ,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAC5E,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;AAEF,KAAK,iBAAiB,GAAG;IACvB,QAAQ,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACpF,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IAC5F,QAAQ,CAAC,cAAc,EAAE,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,KAChD,IAAI,CAAC;CACX,CAAC;AAEF,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;CACvC,CAAC;AAeF,wBAAgB,+BAA+B,CAC7C,eAAe,EAAE,OAAO,GACvB,wBAAwB,CAqB1B;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,wBAAwB,EAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAkChB;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,wBAAwB,EAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAiBN;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,wBAAwB,EAClC,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAaN"}
|
package/dist/preload-bridge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord } from "./protocol.js";
|
|
2
|
-
import { defaultChannelPrefix, } from "./types.js";
|
|
2
|
+
import { assertValidChannelPrefix, defaultChannelPrefix, } from "./types.js";
|
|
3
3
|
function isContextBridgeLike(value) {
|
|
4
4
|
return isRecord(value) && typeof value.exposeInMainWorld === "function";
|
|
5
5
|
}
|
|
@@ -29,7 +29,9 @@ export function resolveElectronRendererBindings(moduleCandidate) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export function createBridgeAdaptersFromBindings(bindings, options) {
|
|
32
|
-
const channelPrefix = options?.channelPrefix
|
|
32
|
+
const channelPrefix = options?.channelPrefix
|
|
33
|
+
? assertValidChannelPrefix(options.channelPrefix)
|
|
34
|
+
: defaultChannelPrefix;
|
|
33
35
|
const { ipcRenderer } = bindings;
|
|
34
36
|
const invoke = (method, payload) => ipcRenderer.invoke(`${channelPrefix.rpc}${method}`, payload);
|
|
35
37
|
const subscribe = (event, listener) => {
|
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,eAAe,EACpB,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AAUvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAMrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AAsEpB,wBAAgB,eAAe,CAC7B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CA0JxD;AAqBD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AAUvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAMrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AAsEpB,wBAAgB,eAAe,CAC7B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CA0JxD;AAqBD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAmG9D;AAUD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,EAE1D,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CA2PpE;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/renderer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as S from "
|
|
1
|
+
import * as S from "effect/Schema";
|
|
2
2
|
import { Cause, Effect, Exit, Stream } from "effect";
|
|
3
3
|
import { exitSchemaFor, isNoErrorSchema, } from "./contract.js";
|
|
4
4
|
import { extractStreamIdFromRaw, formatUnknown, isRecord, parseRpcResponseEnvelope, parseStreamFrame, safelyCall, } from "./protocol.js";
|
|
@@ -183,6 +183,9 @@ export function createEventSubscriber(contract, options) {
|
|
|
183
183
|
});
|
|
184
184
|
return registerUnsubscribe(unsubscribe);
|
|
185
185
|
};
|
|
186
|
+
const streamEvent = (event) => Stream.asyncPush((emit) => Effect.acquireRelease(Effect.sync(() => subscribeEvent(event, (payload) => {
|
|
187
|
+
emit.single(payload);
|
|
188
|
+
})), (unsubscribe) => Effect.sync(unsubscribe)));
|
|
186
189
|
const subscribeByName = (name, handler) => {
|
|
187
190
|
const event = eventMap.get(name);
|
|
188
191
|
if (!event) {
|
|
@@ -220,6 +223,7 @@ export function createEventSubscriber(contract, options) {
|
|
|
220
223
|
return {
|
|
221
224
|
subscribe: subscribeEvent,
|
|
222
225
|
subscribeByName,
|
|
226
|
+
stream: streamEvent,
|
|
223
227
|
dispose,
|
|
224
228
|
};
|
|
225
229
|
}
|
|
@@ -273,7 +277,7 @@ export function createStreamRpcClient(contract, options) {
|
|
|
273
277
|
frameDispatcher.delete(frame.streamId);
|
|
274
278
|
break;
|
|
275
279
|
case "defect":
|
|
276
|
-
handler.defect(frame.message);
|
|
280
|
+
handler.defect(frame.message, true);
|
|
277
281
|
frameDispatcher.delete(frame.streamId);
|
|
278
282
|
break;
|
|
279
283
|
}
|
|
@@ -289,6 +293,9 @@ export function createStreamRpcClient(contract, options) {
|
|
|
289
293
|
const payload = args.length === 0 ? {} : args[0];
|
|
290
294
|
return Stream.asyncPush((emit) => Effect.gen(function* () {
|
|
291
295
|
const streamId = crypto.randomUUID();
|
|
296
|
+
// Once main has sent a terminal frame (end/error/defect) there is
|
|
297
|
+
// nothing left to cancel; the finalizer skips the cancel invoke.
|
|
298
|
+
let serverTerminated = false;
|
|
292
299
|
// 1. Register in dispatch map BEFORE calling invoke
|
|
293
300
|
frameDispatcher.set(streamId, {
|
|
294
301
|
data: (rawPayload) => {
|
|
@@ -321,8 +328,12 @@ export function createStreamRpcClient(contract, options) {
|
|
|
321
328
|
});
|
|
322
329
|
}
|
|
323
330
|
},
|
|
324
|
-
end: () =>
|
|
331
|
+
end: () => {
|
|
332
|
+
serverTerminated = true;
|
|
333
|
+
emit.end();
|
|
334
|
+
},
|
|
325
335
|
error: (err) => {
|
|
336
|
+
serverTerminated = true;
|
|
326
337
|
if (!decodeTypedError) {
|
|
327
338
|
emit.fail(rpcDefect("stream_error_decode_failed", `Stream ${method.name} received typed error but declares NoError`, err));
|
|
328
339
|
return;
|
|
@@ -342,12 +353,19 @@ export function createStreamRpcClient(contract, options) {
|
|
|
342
353
|
emit.fail(rpcDefect("stream_error_decode_failed", `Stream ${method.name} error decode failed: ${formatUnknown(cause)}`, cause));
|
|
343
354
|
}
|
|
344
355
|
},
|
|
345
|
-
defect: (message) =>
|
|
356
|
+
defect: (message, fromServer = false) => {
|
|
357
|
+
if (fromServer) {
|
|
358
|
+
serverTerminated = true;
|
|
359
|
+
}
|
|
360
|
+
emit.fail(rpcDefect("remote_defect", message, undefined));
|
|
361
|
+
},
|
|
346
362
|
});
|
|
347
363
|
// 2. Register cleanup finalizer
|
|
348
364
|
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
349
365
|
frameDispatcher.delete(streamId);
|
|
350
|
-
}).pipe(Effect.andThen(Effect.
|
|
366
|
+
}).pipe(Effect.andThen(Effect.suspend(() => serverTerminated
|
|
367
|
+
? Effect.void
|
|
368
|
+
: Effect.tryPromise(() => invoke(`stream-cancel`, { streamId })).pipe(Effect.ignore)))));
|
|
351
369
|
// 3. Encode input
|
|
352
370
|
const encodedInput = yield* Effect.try({
|
|
353
371
|
try: () => encodeInput(payload),
|
package/dist/types.d.ts
CHANGED
|
@@ -3,18 +3,33 @@ import type * as Runtime from "effect/Runtime";
|
|
|
3
3
|
import type * as Stream from "effect/Stream";
|
|
4
4
|
import type { AnyEvent, AnyMethod, AnyStreamMethod, ExtractMethod, ExtractStreamMethod, RpcContract, RpcError, RpcEventPayload, RpcInput, RpcOutput, StreamChunk, StreamError, StreamInput } from "./contract.ts";
|
|
5
5
|
export type { AnyEvent, AnyMethod, AnyStreamMethod, ErrorSchema, ExtractMethod, ExtractStreamMethod, RpcContract, RpcError, RpcEvent, RpcEventPayload, RpcInput, RpcMethod, RpcOutput, SchemaNoContext, StreamChunk, StreamError, StreamInput, StreamRpcMethod, } from "./contract.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Per-request context passed as the second argument to handlers.
|
|
8
|
+
* Handlers that don't need it can simply omit the parameter.
|
|
9
|
+
*/
|
|
10
|
+
export type RpcHandlerContext = {
|
|
11
|
+
/** The webContents that sent the request, when the transport exposes it. */
|
|
12
|
+
readonly sender: WebContentsLike | null;
|
|
13
|
+
};
|
|
6
14
|
export type Implementations<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>, R = never> = {
|
|
7
|
-
readonly [Name in C["methods"][number]["name"]]: (input: RpcInput<ExtractMethod<C["methods"], Name
|
|
15
|
+
readonly [Name in C["methods"][number]["name"]]: (input: RpcInput<ExtractMethod<C["methods"], Name>>, context: RpcHandlerContext) => Effect.Effect<RpcOutput<ExtractMethod<C["methods"], Name>>, RpcError<ExtractMethod<C["methods"], Name>>, R>;
|
|
8
16
|
};
|
|
9
17
|
export type StreamImplementations<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>, R = never> = {
|
|
10
|
-
readonly [Name in C["streamMethods"][number]["name"]]: (input: StreamInput<ExtractStreamMethod<C["streamMethods"], Name
|
|
18
|
+
readonly [Name in C["streamMethods"][number]["name"]]: (input: StreamInput<ExtractStreamMethod<C["streamMethods"], Name>>, context: RpcHandlerContext) => Stream.Stream<StreamChunk<ExtractStreamMethod<C["streamMethods"], Name>>, StreamError<ExtractStreamMethod<C["streamMethods"], Name>>, R>;
|
|
11
19
|
};
|
|
12
20
|
export type WebContentsLike = {
|
|
13
21
|
readonly id: number;
|
|
14
22
|
readonly isDestroyed: () => boolean;
|
|
15
23
|
readonly send: (channel: string, payload: unknown) => void;
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Optional EventEmitter surface (present on real Electron WebContents).
|
|
26
|
+
* When available, active stream fibers are interrupted as soon as the
|
|
27
|
+
* renderer is destroyed; otherwise termination happens on the next chunk.
|
|
28
|
+
*/
|
|
29
|
+
readonly once?: (event: "destroyed", listener: () => void) => unknown;
|
|
30
|
+
readonly removeListener?: (event: "destroyed", listener: () => void) => unknown;
|
|
31
|
+
};
|
|
32
|
+
type IsEmptyObject<T> = T extends object ? keyof T extends never ? string extends T ? true : false : false : false;
|
|
18
33
|
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" | "stream_invoke_failed" | "stream_handshake_invalid" | "stream_chunk_decode_failed" | "stream_error_decode_failed";
|
|
19
34
|
export declare class RpcDefectError extends Error {
|
|
20
35
|
readonly code: RpcDefectCode;
|
|
@@ -37,6 +52,12 @@ export type ChannelPrefix = {
|
|
|
37
52
|
readonly event: string;
|
|
38
53
|
};
|
|
39
54
|
export declare const defaultChannelPrefix: ChannelPrefix;
|
|
55
|
+
/**
|
|
56
|
+
* RPC and event prefixes must differ: with identical prefixes an event named
|
|
57
|
+
* like a method (or named "sf"/"stream-cancel") would collide with RPC and
|
|
58
|
+
* stream transport channels.
|
|
59
|
+
*/
|
|
60
|
+
export declare function assertValidChannelPrefix(prefix: ChannelPrefix): ChannelPrefix;
|
|
40
61
|
export type DecodeFailureScope = "rpc-request" | "rpc-response" | "event-payload" | "stream-request" | "stream-chunk" | "stream-error";
|
|
41
62
|
export type DecodeFailureContext = {
|
|
42
63
|
readonly scope: DecodeFailureScope;
|
|
@@ -111,11 +132,21 @@ export type EventPublisherOptions = {
|
|
|
111
132
|
readonly diagnostics?: EventPublisherDiagnostics;
|
|
112
133
|
};
|
|
113
134
|
export interface RpcEventPublisher<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> {
|
|
135
|
+
/**
|
|
136
|
+
* Enqueue an event for delivery. Never fails: after `dispose()` the event
|
|
137
|
+
* is silently discarded, and delivery problems surface only through the
|
|
138
|
+
* diagnostics hooks and `stats()`.
|
|
139
|
+
*/
|
|
114
140
|
readonly publish: <E extends C["events"][number]>(event: E, payload: RpcEventPayload<E>) => Effect.Effect<void, never>;
|
|
115
141
|
readonly start: () => void;
|
|
116
142
|
readonly stop: () => void;
|
|
117
143
|
readonly dispose: () => void;
|
|
118
144
|
readonly isRunning: () => boolean;
|
|
145
|
+
/**
|
|
146
|
+
* `dropped` counts failed deliveries, not whole events: an event that
|
|
147
|
+
* reaches two of three windows increments it once (per failed window),
|
|
148
|
+
* as do queue evictions and encoding failures.
|
|
149
|
+
*/
|
|
119
150
|
readonly stats: () => {
|
|
120
151
|
readonly queued: number;
|
|
121
152
|
readonly dropped: number;
|
|
@@ -134,6 +165,12 @@ export type EventSubscriberOptions = {
|
|
|
134
165
|
export interface EventSubscriber<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> {
|
|
135
166
|
readonly subscribe: <E extends C["events"][number]>(event: E, handler: (payload: RpcEventPayload<E>) => void) => () => void;
|
|
136
167
|
readonly subscribeByName: (name: string, handler: (payload: unknown) => void) => () => void;
|
|
168
|
+
/**
|
|
169
|
+
* Effect-native subscription: a Stream of decoded payloads that
|
|
170
|
+
* subscribes when run and unsubscribes when its scope closes.
|
|
171
|
+
* Payloads that fail to decode are skipped (reported via diagnostics).
|
|
172
|
+
*/
|
|
173
|
+
readonly stream: <E extends C["events"][number]>(event: E) => Stream.Stream<RpcEventPayload<E>>;
|
|
137
174
|
readonly dispose: () => void;
|
|
138
175
|
}
|
|
139
176
|
export type OnStreamFrame = (listener: (frame: unknown) => void) => () => void;
|
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,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EAEf,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,QAAQ,EAER,eAAe,EACf,QAAQ,EAER,SAAS,EAET,WAAW,EACX,WAAW,EACX,WAAW,EAEZ,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,QAAQ,EACR,SAAS,EACT,eAAe,EACf,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,SAAS,EACT,SAAS,EACT,eAAe,EACf,WAAW,EACX,WAAW,EACX,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,WAAW,CAAC,SAAS,SAAS,EAAE,EAAE,SAAS,QAAQ,EAAE,EAAE,SAAS,eAAe,EAAE,CAAC,EAC5F,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,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -11,3 +11,14 @@ export const defaultChannelPrefix = {
|
|
|
11
11
|
rpc: "rpc/",
|
|
12
12
|
event: "event/",
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* RPC and event prefixes must differ: with identical prefixes an event named
|
|
16
|
+
* like a method (or named "sf"/"stream-cancel") would collide with RPC and
|
|
17
|
+
* stream transport channels.
|
|
18
|
+
*/
|
|
19
|
+
export function assertValidChannelPrefix(prefix) {
|
|
20
|
+
if (prefix.rpc === prefix.event) {
|
|
21
|
+
throw new Error(`channelPrefix.rpc and channelPrefix.event must differ (both were "${prefix.rpc}").`);
|
|
22
|
+
}
|
|
23
|
+
return prefix;
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-effect-rpc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Typed IPC RPC for Electron, built on Effect and @effect/schema",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect",
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/joaoeira/electron-effect-rpc"
|
|
16
|
+
"url": "git+https://github.com/joaoeira/electron-effect-rpc.git"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"dist"
|
|
19
|
+
"dist",
|
|
20
|
+
"CHANGELOG.md"
|
|
20
21
|
],
|
|
21
22
|
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
22
24
|
"exports": {
|
|
23
25
|
".": {
|
|
24
26
|
"types": "./dist/index.d.ts",
|
|
@@ -66,7 +68,6 @@
|
|
|
66
68
|
"fmt:check": "oxfmt --check ."
|
|
67
69
|
},
|
|
68
70
|
"devDependencies": {
|
|
69
|
-
"@effect/schema": "^0.69.0",
|
|
70
71
|
"@types/node": "^22.0.0",
|
|
71
72
|
"bun-types": "^1.1.0",
|
|
72
73
|
"effect": "^3.11.0",
|
|
@@ -76,8 +77,10 @@
|
|
|
76
77
|
"typescript": "^5.7.0"
|
|
77
78
|
},
|
|
78
79
|
"peerDependencies": {
|
|
79
|
-
"
|
|
80
|
-
"effect": ">=3.0.0",
|
|
80
|
+
"effect": ">=3.10.0",
|
|
81
81
|
"electron": ">=28.0.0"
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=18.0.0"
|
|
82
85
|
}
|
|
83
86
|
}
|