electron-effect-rpc 0.5.0 → 0.7.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 CHANGED
@@ -10,20 +10,24 @@ This package is ESM-only. It targets modern Electron runtimes and assumes an
10
10
  ESM-capable build pipeline.
11
11
 
12
12
  ## Features
13
- - Single shared contract for methods and events.
13
+
14
+ - Single shared contract for methods, events, and streaming RPC.
14
15
  - Single shared kit config to eliminate cross-process prefix drift.
15
16
  - End-to-end schema validation at IPC boundaries.
16
17
  - Effect-first renderer RPC with typed domain and defect channels.
18
+ - Streaming RPC: handlers return `Stream.Stream`, clients consume `Stream.Stream`.
17
19
  - Effect-native main handlers with explicit runtime injection.
18
20
  - Explicit lifecycle handles and bounded event queue backpressure.
19
21
  - Structured diagnostics hooks for decode/protocol/dispatch failures.
20
22
 
21
23
  ## Requirements
24
+
22
25
  - Electron with context isolation enabled.
23
26
  - ESM-capable bundling.
24
27
  - Peer dependencies: `effect`, `@effect/schema`, `electron`.
25
28
 
26
29
  ## Installation
30
+
27
31
  ```sh
28
32
  bun add electron-effect-rpc effect @effect/schema
29
33
  ```
@@ -31,15 +35,12 @@ bun add electron-effect-rpc effect @effect/schema
31
35
  ## Quickstart (Kit-First)
32
36
 
33
37
  ### 1) Define contract and kit once
38
+
34
39
  ```ts
35
40
  import * as S from "@effect/schema/Schema";
36
- import { createIpcKit, defineContract, event, rpc } from "electron-effect-rpc";
41
+ import { createIpcKit, defineContract, event, rpc, streamRpc } from "electron-effect-rpc";
37
42
 
38
- export const GetAppVersion = rpc(
39
- "GetAppVersion",
40
- S.Struct({}),
41
- S.Struct({ version: S.String })
42
- );
43
+ export const GetAppVersion = rpc("GetAppVersion", S.Struct({}), S.Struct({ version: S.String }));
43
44
 
44
45
  export const WorkUnitProgress = event(
45
46
  "WorkUnitProgress",
@@ -47,12 +48,19 @@ export const WorkUnitProgress = event(
47
48
  requestId: S.String,
48
49
  chunk: S.String,
49
50
  done: S.Boolean,
50
- })
51
+ }),
52
+ );
53
+
54
+ export const StreamAiGeneration = streamRpc(
55
+ "StreamAiGeneration",
56
+ S.Struct({ prompt: S.String }),
57
+ S.Struct({ delta: S.String }),
51
58
  );
52
59
 
53
60
  const contract = defineContract({
54
61
  methods: [GetAppVersion] as const,
55
62
  events: [WorkUnitProgress] as const,
63
+ streamMethods: [StreamAiGeneration] as const,
56
64
  });
57
65
 
58
66
  export const ipc = createIpcKit({
@@ -64,9 +72,10 @@ export const ipc = createIpcKit({
64
72
  ```
65
73
 
66
74
  ### 2) Main process
75
+
67
76
  ```ts
68
77
  import { app, ipcMain } from "electron";
69
- import { Effect } from "effect";
78
+ import { Effect, Stream } from "effect";
70
79
  import * as Runtime from "effect/Runtime";
71
80
  import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
72
81
 
@@ -75,20 +84,27 @@ const mainRpc = ipc.main({
75
84
  handlers: {
76
85
  GetAppVersion: () => Effect.succeed({ version: app.getVersion() }),
77
86
  },
87
+ streamHandlers: {
88
+ StreamAiGeneration: ({ prompt }) =>
89
+ Stream.fromIterable(prompt.split(" ")).pipe(Stream.map((word) => ({ delta: word + " " }))),
90
+ },
78
91
  runtime: Runtime.defaultRuntime,
79
92
  getWindows: () => [mainWindow],
80
93
  });
81
94
 
82
95
  mainRpc.start();
83
96
 
84
- void Effect.runPromise(mainRpc.publish(WorkUnitProgress, {
85
- requestId: "req-1",
86
- chunk: "starting",
87
- done: false,
88
- }));
97
+ void Effect.runPromise(
98
+ mainRpc.publish(WorkUnitProgress, {
99
+ requestId: "req-1",
100
+ chunk: "starting",
101
+ done: false,
102
+ }),
103
+ );
89
104
  ```
90
105
 
91
106
  ### 3) Preload
107
+
92
108
  ```ts
93
109
  import { ipc } from "./shared-ipc.ts";
94
110
 
@@ -98,29 +114,39 @@ ipc.preload().expose();
98
114
  This exposes one global by default: `window.api`.
99
115
 
100
116
  ### 4) Renderer
117
+
101
118
  ```ts
102
- import { Effect } from "effect";
119
+ import { Effect, Stream } from "effect";
103
120
  import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
104
121
 
105
- const { client, events } = ipc.renderer(window.api);
122
+ const { client, events, streamClient, dispose } = ipc.renderer(window.api);
106
123
  const { version } = await Effect.runPromise(client.GetAppVersion());
107
124
 
125
+ // Streaming RPC
126
+ await Effect.runPromise(
127
+ streamClient
128
+ .StreamAiGeneration({ prompt: "hello world" })
129
+ .pipe(Stream.runForEach((chunk) => Effect.sync(() => console.log(chunk.delta)))),
130
+ );
131
+
108
132
  const unsubscribe = events.subscribe(WorkUnitProgress, (payload) => {
109
133
  console.log(payload.chunk);
110
134
  });
111
135
 
112
136
  // later
113
137
  unsubscribe();
114
- events.dispose();
138
+ dispose();
115
139
  ```
116
140
 
117
141
  ### 5) Window typing
142
+
118
143
  ```ts
119
144
  declare global {
120
145
  interface Window {
121
146
  api: {
122
147
  invoke: (method: string, payload: unknown) => Promise<unknown>;
123
148
  subscribe: (name: string, handler: (payload: unknown) => void) => () => void;
149
+ onStreamFrame?: (listener: (frame: unknown) => void) => () => void;
124
150
  };
125
151
  }
126
152
  }
@@ -135,7 +161,9 @@ which includes a stable `code` discriminator:
135
161
  `request_encoding_failed`, `invoke_failed`,
136
162
  `success_payload_decoding_failed`, `failure_payload_decoding_failed`,
137
163
  `noerror_contract_violation`, `invalid_response_envelope`,
138
- `legacy_decode_failed`, and `remote_defect`.
164
+ `legacy_decode_failed`, `remote_defect`,
165
+ `stream_invoke_failed`, `stream_handshake_invalid`,
166
+ `stream_chunk_decode_failed`, and `stream_error_decode_failed`.
139
167
 
140
168
  ## Breaking Changes
141
169
 
@@ -174,6 +202,7 @@ await Effect.runPromise(mainRpc.publish(WorkUnitProgress, payload));
174
202
  ## Low-Level APIs (Still Supported)
175
203
 
176
204
  If you need direct control, keep using subpath entry points:
205
+
177
206
  - `electron-effect-rpc/contract`
178
207
  - `electron-effect-rpc/main`
179
208
  - `electron-effect-rpc/renderer`
@@ -184,8 +213,9 @@ If you need direct control, keep using subpath entry points:
184
213
  ## Root API Surface
185
214
 
186
215
  The root entry point exports:
216
+
187
217
  - `createIpcKit`
188
- - `rpc`, `event`, `defineContract`, `NoError`
218
+ - `rpc`, `event`, `streamRpc`, `defineContract`, `NoError`
189
219
  - Types: `IpcKit`, `IpcKitOptions`, `IpcMainHandle`, `IpcBridge`, `IpcBridgeGlobal`
190
220
 
191
221
  Low-level factories like `createRpcClient` remain subpath-only by design.
@@ -193,15 +223,19 @@ Low-level factories like `createRpcClient` remain subpath-only by design.
193
223
  ## Tutorials
194
224
 
195
225
  For deeper walkthroughs and production guidance:
226
+
196
227
  - [Tutorial Index](./docs/tutorials/README.md)
197
228
  - [First RPC: Main + Preload + Renderer](./docs/tutorials/01-first-rpc.md)
198
229
  - [Typed Errors, Defects, and Diagnostics](./docs/tutorials/02-typed-errors-defects-diagnostics.md)
199
230
  - [Events, Lifecycle, and Backpressure](./docs/tutorials/03-events-lifecycle-backpressure.md)
231
+ - [Streaming RPC](./docs/tutorials/04-streaming-rpc.md)
200
232
 
201
233
  ## Conventions
234
+
202
235
  - Relative imports use `.ts` extensions.
203
236
  - Package imports are extensionless.
204
237
  - No `index.ts` barrel files in subpath modules.
205
238
 
206
239
  ## License
240
+
207
241
  MIT
@@ -20,6 +20,22 @@ export interface RpcEvent<Payload extends SchemaNoContext, Context extends Schem
20
20
  export declare function event<const Name extends string, Payload extends SchemaNoContext, Context extends SchemaNoContext>(name: Name, payload: Payload, context: Context): RpcEvent<Payload, Context, Name>;
21
21
  export declare function event<const Name extends string, Payload extends SchemaNoContext>(name: Name, payload: Payload): RpcEvent<Payload, null, Name>;
22
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>;
23
+ export interface StreamRpcMethod<Name extends string, Req extends SchemaNoContext, Chunk extends SchemaNoContext, Err extends ErrorSchema = NoError> {
24
+ readonly _tag: "StreamRpcMethod";
25
+ readonly name: Name;
26
+ readonly req: Req;
27
+ readonly chunk: Chunk;
28
+ readonly err: Err;
29
+ }
30
+ export declare function streamRpc<const Name extends string, Req extends SchemaNoContext, Chunk extends SchemaNoContext, Err extends ErrorSchema>(name: Name, req: Req, chunk: Chunk, err: Err): StreamRpcMethod<Name, Req, Chunk, Err>;
31
+ export declare function streamRpc<const Name extends string, Req extends SchemaNoContext, Chunk extends SchemaNoContext>(name: Name, req: Req, chunk: Chunk): StreamRpcMethod<Name, Req, Chunk, NoError>;
32
+ export type AnyStreamMethod = StreamRpcMethod<string, SchemaNoContext, SchemaNoContext, ErrorSchema>;
33
+ export type StreamInput<M extends AnyStreamMethod> = S.Schema.Type<M["req"]>;
34
+ export type StreamChunk<M extends AnyStreamMethod> = S.Schema.Type<M["chunk"]>;
35
+ export type StreamError<M extends AnyStreamMethod> = S.Schema.Type<M["err"]>;
36
+ export type ExtractStreamMethod<Methods extends readonly AnyStreamMethod[], Name extends string> = Extract<Methods[number], {
37
+ readonly name: Name;
38
+ }>;
23
39
  export type AnyMethod = RpcMethod<string, SchemaNoContext, SchemaNoContext, ErrorSchema>;
24
40
  export type AnyEvent = RpcEvent<SchemaNoContext, SchemaNoContext | null, string>;
25
41
  export type RpcInput<M extends AnyMethod> = S.Schema.Type<M["req"]>;
@@ -30,12 +46,18 @@ export type RpcEventPayload<E extends AnyEvent> = S.Schema.Type<E["payload"]>;
30
46
  export type ExtractMethod<Methods extends readonly AnyMethod[], Name extends string> = Extract<Methods[number], {
31
47
  readonly name: Name;
32
48
  }>;
33
- export interface RpcContract<Methods extends ReadonlyArray<AnyMethod>, Events extends ReadonlyArray<AnyEvent>> {
49
+ export interface RpcContract<Methods extends ReadonlyArray<AnyMethod>, Events extends ReadonlyArray<AnyEvent>, StreamMethods extends ReadonlyArray<AnyStreamMethod> = readonly []> {
34
50
  readonly methods: Methods;
35
51
  readonly events: Events;
52
+ readonly streamMethods: StreamMethods;
36
53
  }
37
54
  export declare function defineContract<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(input: {
38
55
  readonly methods: Methods;
39
56
  readonly events: Events;
40
- }): RpcContract<Methods, Events>;
57
+ }): RpcContract<Methods, Events, readonly []>;
58
+ export declare function defineContract<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>, const StreamMethods extends ReadonlyArray<AnyStreamMethod>>(input: {
59
+ readonly methods: Methods;
60
+ readonly events: Events;
61
+ readonly streamMethods: StreamMethods;
62
+ }): RpcContract<Methods, Events, StreamMethods>;
41
63
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,uBAAuB,CAAC;AAE3C,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;AAEpD,eAAO,MAAM,OAAO,gBAAU,CAAC;AAC/B,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,OAAO,CAAC;AAEpD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,IAAI,OAAO,CAEtE;AAED,MAAM,WAAW,SAAS,CACxB,IAAI,SAAS,MAAM,EACnB,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,WAAW,GAAG,OAAO;IAEjC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;CACnB;AAED,wBAAgB,GAAG,CACjB,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,WAAW,EACvB,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE5E,wBAAgB,GAAG,CACjB,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,eAAe,EAC3B,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAWtE,MAAM,WAAW,QAAQ,CACvB,OAAO,SAAS,eAAe,EAC/B,OAAO,SAAS,eAAe,GAAG,IAAI,EACtC,IAAI,SAAS,MAAM,GAAG,MAAM;IAE5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,KAAK,CACnB,KAAK,CAAC,IAAI,SAAS,MAAM,EACzB,OAAO,SAAS,eAAe,EAC/B,OAAO,SAAS,eAAe,EAC/B,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAEpF,wBAAgB,KAAK,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,EAAE,OAAO,SAAS,eAAe,EAC9E,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,GACf,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAUjC,eAAO,MAAM,aAAa,GACxB,IAAI,SAAS,MAAM,EACnB,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,eAAe,EAC3B,GAAG,SAAS,WAAW,EAEvB,QAAQ,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,+BAMpC,CAAC;AAEL,MAAM,MAAM,SAAS,GAAG,SAAS,CAC/B,MAAM,EACN,eAAe,EACf,eAAe,EACf,WAAW,CACZ,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AAEjF,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAErE,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAEpE,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAE9E,gEAAgE;AAChE,MAAM,MAAM,aAAa,CACvB,OAAO,SAAS,SAAS,SAAS,EAAE,EACpC,IAAI,SAAS,MAAM,IACjB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAEtD,MAAM,WAAW,WAAW,CAC1B,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EACxC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC;IAEtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAiBD,wBAAgB,cAAc,CAC5B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAE5C,KAAK,EAAE;IACL,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACA,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CA0B9B"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
package/dist/contract.js CHANGED
@@ -14,6 +14,9 @@ export const exitSchemaFor = (method) => S.Exit({
14
14
  failure: method.err,
15
15
  defect: S.Defect,
16
16
  });
17
+ export function streamRpc(name, req, chunk, err = NoError) {
18
+ return { _tag: "StreamRpcMethod", name, req, chunk, err };
19
+ }
17
20
  function collectDuplicates(names) {
18
21
  const counts = new Map();
19
22
  const duplicates = [];
@@ -26,15 +29,35 @@ function collectDuplicates(names) {
26
29
  }
27
30
  return duplicates;
28
31
  }
32
+ const RESERVED_STREAM_NAMES = new Set(["sf", "stream-cancel"]);
33
+ function hasReservedStreamPrefix(name) {
34
+ return name.startsWith("stream/");
35
+ }
36
+ function validateReservedNames(names, kind) {
37
+ for (const name of names) {
38
+ if (RESERVED_STREAM_NAMES.has(name)) {
39
+ throw new Error(`${kind} name "${name}" is reserved for internal stream transport.`);
40
+ }
41
+ if (hasReservedStreamPrefix(name)) {
42
+ throw new Error(`${kind} name "${name}" must not start with "stream/" (reserved for internal stream transport).`);
43
+ }
44
+ }
45
+ }
29
46
  export function defineContract(input) {
30
47
  const { methods, events } = input;
48
+ const streamMethods = input.streamMethods ?? [];
31
49
  if (!Array.isArray(methods)) {
32
50
  throw new Error("RPC contract methods must be an array.");
33
51
  }
34
52
  if (!Array.isArray(events)) {
35
53
  throw new Error("RPC contract events must be an array.");
36
54
  }
37
- const duplicateMethods = collectDuplicates(methods.map((method) => method.name));
55
+ if (!Array.isArray(streamMethods)) {
56
+ throw new Error("RPC contract streamMethods must be an array.");
57
+ }
58
+ const methodNames = methods.map((method) => method.name);
59
+ const streamMethodNames = streamMethods.map((m) => m.name);
60
+ const duplicateMethods = collectDuplicates(methodNames);
38
61
  if (duplicateMethods.length > 0) {
39
62
  throw new Error(`Duplicate RPC method name(s): ${duplicateMethods.join(", ")}`);
40
63
  }
@@ -42,5 +65,15 @@ export function defineContract(input) {
42
65
  if (duplicateEvents.length > 0) {
43
66
  throw new Error(`Duplicate RPC event name(s): ${duplicateEvents.join(", ")}`);
44
67
  }
45
- return input;
68
+ const duplicateStreamMethods = collectDuplicates(streamMethodNames);
69
+ if (duplicateStreamMethods.length > 0) {
70
+ throw new Error(`Duplicate stream method name(s): ${duplicateStreamMethods.join(", ")}`);
71
+ }
72
+ const crossDuplicates = collectDuplicates([...methodNames, ...streamMethodNames]);
73
+ if (crossDuplicates.length > 0) {
74
+ throw new Error(`Name collision between methods and streamMethods: ${crossDuplicates.join(", ")}`);
75
+ }
76
+ validateReservedNames(methodNames, "Method");
77
+ validateReservedNames(streamMethodNames, "Stream method");
78
+ return { methods, events, streamMethods };
46
79
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { createIpcKit } from "./kit.ts";
2
- export { defineContract, event, NoError, rpc } from "./contract.ts";
3
- export type { IpcBridge, IpcBridgeGlobal, IpcKit, IpcKitOptions, IpcMainHandle, } from "./kit.ts";
2
+ export { defineContract, event, NoError, rpc, streamRpc } from "./contract.ts";
3
+ export type { IpcBridge, IpcBridgeGlobal, IpcKit, IpcKitOptions, IpcMainHandle } from "./kit.ts";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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"}
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,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export { createIpcKit } from "./kit.js";
2
- export { defineContract, event, NoError, rpc } from "./contract.js";
2
+ export { defineContract, event, NoError, rpc, streamRpc } from "./contract.js";
package/dist/kit.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  import { Effect } from "effect";
2
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";
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";
5
5
  export type IpcBridge = {
6
6
  readonly invoke: RpcInvoke;
7
7
  readonly subscribe: EventSubscribe;
8
+ readonly onStreamFrame?: OnStreamFrame;
8
9
  };
9
10
  export type IpcBridgeGlobal<Name extends string = "api"> = {
10
11
  readonly [K in Name]: IpcBridge;
11
12
  };
12
- export type IpcKitOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
13
+ export type IpcKitOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> = {
13
14
  readonly contract: C;
14
15
  readonly channelPrefix?: ChannelPrefix;
15
16
  readonly bridge?: {
@@ -19,19 +20,21 @@ export type IpcKitOptions<C extends RpcContract<readonly AnyMethod[], readonly A
19
20
  readonly rpc?: RpcResponseDecodeMode;
20
21
  readonly events?: EventDecodeMode;
21
22
  };
23
+ readonly streamBuffer?: StreamBufferOptions;
22
24
  };
23
- type IpcMainOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>, R> = {
25
+ type IpcMainOptions<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>, R> = {
24
26
  readonly ipcMain: IpcMainLike;
25
27
  readonly handlers: Implementations<C, R>;
26
28
  readonly runtime: Runtime.Runtime<R>;
27
29
  readonly getWindows: () => ReadonlyArray<RendererWindowLike>;
28
30
  readonly maxQueueSize?: number;
31
+ readonly streamHandlers?: StreamImplementations<C, R>;
29
32
  readonly diagnostics?: {
30
33
  readonly rpc?: RpcEndpointDiagnostics;
31
34
  readonly events?: EventPublisherDiagnostics;
32
35
  };
33
36
  };
34
- export type IpcMainHandle<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
37
+ export type IpcMainHandle<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> = {
35
38
  readonly endpoint: RpcEndpoint;
36
39
  readonly publisher: RpcEventPublisher<C>;
37
40
  readonly start: () => void;
@@ -44,13 +47,14 @@ export type IpcMainHandle<C extends RpcContract<readonly AnyMethod[], readonly A
44
47
  readonly dropped: number;
45
48
  };
46
49
  };
47
- export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
50
+ export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[], readonly AnyStreamMethod[]>> = {
48
51
  readonly contract: C;
49
52
  readonly config: {
50
53
  readonly channelPrefix: ChannelPrefix;
51
54
  readonly bridgeGlobal: string;
52
55
  readonly rpcDecodeMode: RpcResponseDecodeMode;
53
56
  readonly eventDecodeMode: EventDecodeMode;
57
+ readonly streamBuffer: StreamBufferOptions;
54
58
  };
55
59
  readonly main: <R>(options: IpcMainOptions<C, R>) => IpcMainHandle<C>;
56
60
  readonly preload: (options?: {
@@ -63,8 +67,10 @@ export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent
63
67
  readonly renderer: (bridge: IpcBridge) => {
64
68
  readonly client: RpcClient<C>;
65
69
  readonly events: EventSubscriber<C>;
70
+ readonly streamClient: StreamRpcClient<C>;
71
+ readonly dispose: () => void;
66
72
  };
67
73
  };
68
- export declare function createIpcKit<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(options: IpcKitOptions<RpcContract<Methods, Events>>): IpcKit<RpcContract<Methods, Events>>;
74
+ export declare function createIpcKit<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>, const StreamMethods extends ReadonlyArray<AnyStreamMethod> = readonly []>(options: IpcKitOptions<RpcContract<Methods, Events, StreamMethods>>): IpcKit<RpcContract<Methods, Events, StreamMethods>>;
69
75
  export {};
70
76
  //# sourceMappingURL=kit.d.ts.map
package/dist/kit.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../src/kit.ts"],"names":[],"mappings":"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"}
package/dist/kit.js CHANGED
@@ -1,9 +1,20 @@
1
1
  import { Effect } from "effect";
2
2
  import { createEventPublisher, createRpcEndpoint } from "./main.js";
3
3
  import { exposeIpcBridge, createBridgeAdapters } from "./preload.js";
4
- import { createEventSubscriber, createRpcClient } from "./renderer.js";
4
+ import { createEventSubscriber, createRpcClient, createStreamRpcClient } from "./renderer.js";
5
5
  import { defaultChannelPrefix, } from "./types.js";
6
6
  export function createIpcKit(options) {
7
+ const normalizeStreamBuffer = (buffer) => {
8
+ if (!buffer || buffer.bufferSize === "unbounded") {
9
+ const resolved = { bufferSize: "unbounded" };
10
+ return Object.freeze(resolved);
11
+ }
12
+ const resolved = {
13
+ bufferSize: buffer.bufferSize,
14
+ strategy: buffer.strategy,
15
+ };
16
+ return Object.freeze(resolved);
17
+ };
7
18
  const contract = options.contract;
8
19
  const channelPrefix = options.channelPrefix
9
20
  ? { ...options.channelPrefix }
@@ -11,11 +22,13 @@ export function createIpcKit(options) {
11
22
  const bridgeGlobal = options.bridge?.global ?? "api";
12
23
  const rpcDecodeMode = options.decode?.rpc ?? "envelope";
13
24
  const eventDecodeMode = options.decode?.events ?? "safe";
25
+ const streamBuffer = normalizeStreamBuffer(options.streamBuffer);
14
26
  const main = (mainOptions) => {
15
27
  const endpoint = createRpcEndpoint(contract, mainOptions.ipcMain, mainOptions.handlers, {
16
28
  runtime: mainOptions.runtime,
17
29
  channelPrefix,
18
30
  diagnostics: mainOptions.diagnostics?.rpc,
31
+ streamHandlers: mainOptions.streamHandlers,
19
32
  });
20
33
  const publisher = createEventPublisher(contract, {
21
34
  getWindows: mainOptions.getWindows,
@@ -108,6 +121,20 @@ export function createIpcKit(options) {
108
121
  };
109
122
  };
110
123
  const renderer = (bridge) => {
124
+ const hasStreamMethods = (contract.streamMethods?.length ?? 0) > 0;
125
+ if (hasStreamMethods && !bridge.onStreamFrame) {
126
+ throw new Error("Contract defines stream methods but bridge.onStreamFrame is missing. " +
127
+ "Ensure the preload bridge exposes onStreamFrame.");
128
+ }
129
+ let streamHandle = null;
130
+ if (hasStreamMethods && bridge.onStreamFrame) {
131
+ streamHandle = createStreamRpcClient(contract, {
132
+ invoke: bridge.invoke,
133
+ onStreamFrame: bridge.onStreamFrame,
134
+ streamBuffer,
135
+ });
136
+ }
137
+ const emptyStreamClient = Object.create(null);
111
138
  return {
112
139
  client: createRpcClient(contract, {
113
140
  invoke: bridge.invoke,
@@ -117,6 +144,10 @@ export function createIpcKit(options) {
117
144
  subscribe: bridge.subscribe,
118
145
  decodeMode: eventDecodeMode,
119
146
  }),
147
+ streamClient: streamHandle?.client ?? emptyStreamClient,
148
+ dispose: () => {
149
+ streamHandle?.dispose();
150
+ },
120
151
  };
121
152
  };
122
153
  return {
@@ -126,6 +157,7 @@ export function createIpcKit(options) {
126
157
  bridgeGlobal,
127
158
  rpcDecodeMode,
128
159
  eventDecodeMode,
160
+ streamBuffer,
129
161
  },
130
162
  main,
131
163
  preload,
package/dist/main.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { RpcContract } from "./contract.ts";
1
+ import type { AnyStreamMethod, RpcContract } from "./contract.ts";
2
2
  import { type AnyEvent, type AnyMethod, type EventPublisherOptions, type Implementations, type IpcMainLike, type RpcEndpoint, type RpcEndpointOptions, type RpcEventPublisher } from "./types.ts";
3
- export declare function createRpcEndpoint<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>, R = never>(contract: RpcContract<Methods, Events>, ipc: IpcMainLike, implementations: Implementations<RpcContract<Methods, Events>, R>, options: RpcEndpointOptions<R>): RpcEndpoint;
4
- export declare function createEventPublisher<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(_contract: RpcContract<Methods, Events>, options: EventPublisherOptions): RpcEventPublisher<RpcContract<Methods, Events>>;
3
+ export declare function createRpcEndpoint<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>, const StreamMethods extends ReadonlyArray<AnyStreamMethod> = readonly [], R = never>(contract: RpcContract<Methods, Events, StreamMethods>, ipc: IpcMainLike, implementations: Implementations<RpcContract<Methods, Events, StreamMethods>, R>, options: RpcEndpointOptions<RpcContract<Methods, Events, StreamMethods>, R>): RpcEndpoint;
4
+ export declare function createEventPublisher<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>, const StreamMethods extends ReadonlyArray<AnyStreamMethod> = readonly []>(_contract: RpcContract<Methods, Events, StreamMethods>, options: EventPublisherOptions): RpcEventPublisher<RpcContract<Methods, Events, StreamMethods>>;
5
5
  //# sourceMappingURL=main.d.ts.map
@@ -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,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,CAmNjD"}
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,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAGvB,MAAM,YAAY,CAAC;AAkCpB,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,CAwbb;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"}