electron-effect-rpc 0.2.0 → 0.3.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
@@ -1,24 +1,26 @@
1
1
  # electron-effect-rpc
2
2
 
3
- Typed IPC RPC for Electron, built on Effect and @effect/schema. This library
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
- This package is ESM-only. It targets modern Electron runtimes (current project
8
- uses Electron 38) and assumes ESM-capable bundling.
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
- - End-to-end type safety using @effect/schema.
13
- - Promise-based renderer client with typed errors.
14
- - Effect-based main handlers with explicit runtime injection.
15
- - Explicit lifecycle handles for main-process RPC and event publishing.
16
- - Bounded event queue with drop-oldest backpressure.
14
+ - Single shared kit config to eliminate cross-process prefix drift.
15
+ - End-to-end schema validation at IPC boundaries.
16
+ - Promise-based renderer RPC with typed domain errors.
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 build pipeline.
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
- If you are in a monorepo workspace, add the dependency to the target package
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/contract";
36
+ import { createIpcKit, defineContract, event, rpc } from "electron-effect-rpc";
54
37
 
55
38
  export const GetAppVersion = rpc(
56
39
  "GetAppVersion",
@@ -67,218 +50,121 @@ export const WorkUnitProgress = event(
67
50
  })
68
51
  );
69
52
 
70
- const methods = [GetAppVersion] as const;
71
- const events = [WorkUnitProgress] as const;
72
-
73
- export const contract = defineContract({ methods, events });
74
- ```
75
-
76
- ### Errors
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`.
53
+ const contract = defineContract({
54
+ methods: [GetAppVersion] as const,
55
+ events: [WorkUnitProgress] as const,
56
+ });
79
57
 
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
- );
58
+ export const ipc = createIpcKit({
59
+ contract,
60
+ channelPrefix: { rpc: "rpc/", event: "event/" },
61
+ bridge: { global: "api" },
62
+ decode: { rpc: "envelope", events: "safe" },
63
+ });
95
64
  ```
96
65
 
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 { createRpcEndpoint, createEventPublisher } from "electron-effect-rpc/main";
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 endpoint = createRpcEndpoint(contract, ipcMain, implementations, {
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
- publisher.publish(WorkUnitProgress, {
82
+ mainRpc.start();
83
+
84
+ void mainRpc.emit(WorkUnitProgress, {
122
85
  requestId: "req-1",
123
- chunk: "working...",
86
+ chunk: "starting",
124
87
  done: false,
125
88
  });
126
- ```
127
89
 
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();
90
+ // Effect-native alternative:
91
+ // void Effect.runPromise(mainRpc.publish(WorkUnitProgress, {...}));
140
92
  ```
141
93
 
142
- ### Preload: expose bridge globals
94
+ ### 3) Preload
143
95
  ```ts
144
- import { exposeRpcBridge } from "electron-effect-rpc/preload";
145
-
146
- exposeRpcBridge();
147
- ```
148
-
149
- Defaults:
150
- - RPC global: `window.rpc.invoke(method, payload)`
151
- - Events global: `window.events.subscribe(name, handler)`
152
- - Channel prefix: `rpc/` and `event/`
96
+ import { ipc } from "./shared-ipc.ts";
153
97
 
154
- You can override globals and prefixes:
155
- ```ts
156
- exposeRpcBridge({
157
- rpcGlobal: "rpcApi",
158
- eventsGlobal: "rpcEvents",
159
- channelPrefix: { rpc: "rpc/", event: "events/" },
160
- });
98
+ ipc.preload().expose();
161
99
  ```
162
100
 
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
- ```
101
+ This exposes one global by default: `window.api`.
171
102
 
172
- ### Renderer: create client and subscriber
103
+ ### 4) Renderer
173
104
  ```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
- });
105
+ import { ipc, WorkUnitProgress } from "./shared-ipc.ts";
182
106
 
107
+ const { client, events } = ipc.renderer(window.api);
183
108
  const { version } = await client.GetAppVersion();
184
109
 
185
- events.subscribe(WorkUnitProgress, (payload) => {
110
+ const unsubscribe = events.subscribe(WorkUnitProgress, (payload) => {
186
111
  console.log(payload.chunk);
187
112
  });
188
- ```
189
113
 
190
- ### Window type augmentation
191
- If you expose globals in preload, add a local `globals.d.ts`:
114
+ // later
115
+ unsubscribe();
116
+ events.dispose();
117
+ ```
192
118
 
119
+ ### 5) Window typing
193
120
  ```ts
194
121
  declare global {
195
122
  interface Window {
196
- rpc: {
123
+ api: {
197
124
  invoke: (method: string, payload: unknown) => Promise<unknown>;
198
- };
199
- events: {
200
125
  subscribe: (name: string, handler: (payload: unknown) => void) => () => void;
201
126
  };
202
127
  }
203
128
  }
204
129
  ```
205
130
 
206
- ## Testing
207
-
208
- ### Renderer client tests
209
- Use the testing helpers to stub invoke behavior:
210
-
211
- ```ts
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
- });
222
-
223
- const client = createRpcClient(contract, { invoke });
224
- await client.GetAppVersion();
225
-
226
- expect(invoke.invocations).toEqual([
227
- { method: "GetAppVersion", payload: {} },
228
- ]);
229
- ```
230
-
231
- ### Main process tests
232
- You can stub `IpcMainLike` and collect registered handlers:
131
+ ## Error Model
233
132
 
234
- ```ts
235
- import * as Runtime from "effect/Runtime";
236
- import { createRpcEndpoint } from "electron-effect-rpc/main";
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();
254
- ```
133
+ Domain failures are modeled with tagged error schemas and are re-thrown in the
134
+ renderer as those same error classes. Unexpected failures, transport defects,
135
+ and protocol mismatches are surfaced as `RpcDefectError`.
255
136
 
256
- ## Error Handling
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`.
137
+ ## Low-Level APIs (Still Supported)
261
138
 
262
- ## API Surface
263
-
264
- Entry points:
139
+ If you need direct control, keep using subpath entry points:
265
140
  - `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
141
  - `electron-effect-rpc/main`
270
- - `createRpcEndpoint`, `createEventPublisher`
271
142
  - `electron-effect-rpc/renderer`
272
- - `createRpcClient`, `createEventSubscriber`, `RpcDefectError`
273
143
  - `electron-effect-rpc/preload`
274
- - `exposeRpcBridge`, `createBridgeAdapters`
144
+ - `electron-effect-rpc/types`
275
145
  - `electron-effect-rpc/testing`
276
- - `createInvokeStub`, `createDeferred`
146
+
147
+ ## Root API Surface
148
+
149
+ The root entry point exports:
150
+ - `createIpcKit`
151
+ - `rpc`, `event`, `defineContract`, `NoError`
152
+ - Types: `IpcKit`, `IpcKitOptions`, `IpcMainHandle`, `IpcBridge`, `IpcBridgeGlobal`
153
+
154
+ Low-level factories like `createRpcClient` remain subpath-only by design.
155
+
156
+ ## Tutorials
157
+
158
+ For deeper walkthroughs and production guidance:
159
+ - [Tutorial Index](./docs/tutorials/README.md)
160
+ - [First RPC: Main + Preload + Renderer](./docs/tutorials/01-first-rpc.md)
161
+ - [Typed Errors, Defects, and Diagnostics](./docs/tutorials/02-typed-errors-defects-diagnostics.md)
162
+ - [Events, Lifecycle, and Backpressure](./docs/tutorials/03-events-lifecycle-backpressure.md)
277
163
 
278
164
  ## Conventions
279
165
  - Relative imports use `.ts` extensions.
280
166
  - Package imports are extensionless.
281
- - No `index.ts` barrel files.
167
+ - No `index.ts` barrel files in subpath modules.
282
168
 
283
169
  ## License
284
170
  MIT
@@ -0,0 +1,4 @@
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";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -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
@@ -0,0 +1,2 @@
1
+ export { createIpcKit } from "./kit.js";
2
+ export { defineContract, event, NoError, rpc } from "./contract.js";
package/dist/kit.d.ts ADDED
@@ -0,0 +1,71 @@
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 emit: <E extends C["events"][number]>(event: E, payload: RpcEventPayload<E>) => Promise<void>;
43
+ readonly stats: () => {
44
+ readonly queued: number;
45
+ readonly dropped: number;
46
+ };
47
+ };
48
+ export type IpcKit<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
49
+ readonly contract: C;
50
+ readonly config: {
51
+ readonly channelPrefix: ChannelPrefix;
52
+ readonly bridgeGlobal: string;
53
+ readonly rpcDecodeMode: RpcResponseDecodeMode;
54
+ readonly eventDecodeMode: EventDecodeMode;
55
+ };
56
+ readonly main: <R>(options: IpcMainOptions<C, R>) => IpcMainHandle<C>;
57
+ readonly preload: (options?: {
58
+ readonly global?: string;
59
+ }) => {
60
+ readonly global: string;
61
+ readonly bridge: IpcBridge;
62
+ readonly expose: () => void;
63
+ };
64
+ readonly renderer: (bridge: IpcBridge) => {
65
+ readonly client: RpcClient<C>;
66
+ readonly events: EventSubscriber<C>;
67
+ };
68
+ };
69
+ export declare function createIpcKit<const Methods extends ReadonlyArray<AnyMethod>, const Events extends ReadonlyArray<AnyEvent>>(options: IpcKitOptions<RpcContract<Methods, Events>>): IpcKit<RpcContract<Methods, Events>>;
70
+ export {};
71
+ //# 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,138 @@
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
+ function emit(event, payload) {
84
+ return Effect.runPromise(publisher.publish(event, payload));
85
+ }
86
+ return {
87
+ endpoint,
88
+ publisher,
89
+ start,
90
+ stop,
91
+ dispose,
92
+ isRunning,
93
+ publish,
94
+ emit,
95
+ stats: publisher.stats,
96
+ };
97
+ };
98
+ const preload = (preloadOptions) => {
99
+ const global = preloadOptions?.global ?? bridgeGlobal;
100
+ const bridge = createBridgeAdapters({
101
+ channelPrefix,
102
+ });
103
+ return {
104
+ global,
105
+ bridge,
106
+ expose: () => {
107
+ exposeIpcBridge({
108
+ global,
109
+ channelPrefix,
110
+ });
111
+ },
112
+ };
113
+ };
114
+ const renderer = (bridge) => {
115
+ return {
116
+ client: createRpcClient(contract, {
117
+ invoke: bridge.invoke,
118
+ rpcDecodeMode,
119
+ }),
120
+ events: createEventSubscriber(contract, {
121
+ subscribe: bridge.subscribe,
122
+ decodeMode: eventDecodeMode,
123
+ }),
124
+ };
125
+ };
126
+ return {
127
+ contract,
128
+ config: {
129
+ channelPrefix,
130
+ bridgeGlobal,
131
+ rpcDecodeMode,
132
+ eventDecodeMode,
133
+ },
134
+ main,
135
+ preload,
136
+ renderer,
137
+ };
138
+ }
@@ -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,CA4Kb;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,CA8KjD"}
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
- for (const [channel, listener] of listeners) {
113
- ipc.handle(channel, listener);
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
- ipc.removeHandler(channel);
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
- stop();
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
@@ -1 +1 @@
1
- {"version":3,"file":"preload.d.ts","sourceRoot":"","sources":["../src/preload.ts"],"names":[],"mappings":"AACA,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,wBAAgB,oBAAoB,CAClC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAsBhB;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAerE"}
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 { contextBridge, ipcRenderer } from "electron";
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
+ }
@@ -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?: 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>>;
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
@@ -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;AAEvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAEtB,MAAM,YAAY,CAAC;AAuDpB,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,CAAC,EAAE,gBAAgB,GACzB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAqHzC;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,CAAC,EAAE,sBAAsB,GAC/B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CA+E/C;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,WAAW,EAIjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAEtB,MAAM,YAAY,CAAC;AAuDpB,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,CAwIzC;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
@@ -54,7 +54,18 @@ export function createRpcClient(contract, options) {
54
54
  });
55
55
  throw new Error(`RPC ${method.name} request encoding failed: ${formatUnknown(cause)}`);
56
56
  }
57
- const raw = await invoke(method.name, encoded);
57
+ let raw;
58
+ try {
59
+ raw = await invoke(method.name, encoded);
60
+ }
61
+ catch (cause) {
62
+ safelyCall(diagnostics?.onProtocolError, {
63
+ method: method.name,
64
+ response: undefined,
65
+ cause,
66
+ });
67
+ throw new RpcDefectError(`RPC ${method.name} invoke failed: ${formatUnknown(cause)}`, cause);
68
+ }
58
69
  const envelope = parseRpcResponseEnvelope(raw);
59
70
  if (envelope) {
60
71
  switch (envelope.type) {
@@ -117,8 +128,11 @@ export function createRpcClient(contract, options) {
117
128
  const client = Object.create(null);
118
129
  const clientRecord = client;
119
130
  for (const method of contract.methods) {
120
- const caller = (input) => {
121
- const payload = input ?? S.decodeUnknownSync(method.req)({});
131
+ const decodeDefaultInput = S.decodeUnknownSync(method.req);
132
+ const caller = (...args) => {
133
+ const payload = args.length === 0
134
+ ? decodeDefaultInput({})
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
- unsubscribe();
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,7 +5,7 @@ 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;
8
+ type IsEmptyObject<T> = T extends object ? keyof T extends never ? true : false : false;
9
9
  export type RpcCaller<M extends AnyMethod> = IsEmptyObject<RpcInput<M>> extends true ? () => Promise<RpcOutput<M>> : (input: RpcInput<M>) => Promise<RpcOutput<M>>;
10
10
  export type RpcClient<C extends RpcContract<readonly AnyMethod[], readonly AnyEvent[]>> = {
11
11
  readonly [Name in C["methods"][number]["name"]]: RpcCaller<ExtractMethod<C["methods"], Name>>;
@@ -37,7 +37,7 @@ export type DispatchFailureContext = {
37
37
  readonly payload: unknown;
38
38
  readonly cause: unknown;
39
39
  };
40
- export type DroppedEventReason = "queue_full" | "encoding_failed";
40
+ export type DroppedEventReason = "queue_full" | "encoding_failed" | "window_unavailable" | "dispatch_failed";
41
41
  export type DroppedEventContext = {
42
42
  readonly event: string;
43
43
  readonly payload: unknown;
@@ -52,7 +52,7 @@ export type RpcClientDiagnostics = {
52
52
  readonly onProtocolError?: (context: ProtocolErrorContext) => void;
53
53
  };
54
54
  export type RpcClientOptions = {
55
- readonly invoke?: RpcInvoke;
55
+ readonly invoke: RpcInvoke;
56
56
  readonly diagnostics?: RpcClientDiagnostics;
57
57
  readonly rpcDecodeMode?: RpcResponseDecodeMode;
58
58
  };
@@ -112,7 +112,7 @@ export type EventSubscriberDiagnostics = {
112
112
  readonly onDecodeFailure?: (context: DecodeFailureContext) => void;
113
113
  };
114
114
  export type EventSubscriberOptions = {
115
- readonly subscribe?: EventSubscribe;
115
+ readonly subscribe: EventSubscribe;
116
116
  readonly decodeMode?: EventDecodeMode;
117
117
  readonly diagnostics?: EventSubscriberDiagnostics;
118
118
  };
@@ -121,4 +121,5 @@ export interface EventSubscriber<C extends RpcContract<readonly AnyMethod[], rea
121
121
  readonly subscribeByName: (name: string, handler: (payload: unknown) => void) => () => void;
122
122
  readonly dispose: () => void;
123
123
  }
124
+ export type { IpcBridge, IpcBridgeGlobal, IpcKit, IpcKitOptions, IpcMainHandle, } from "./kit.ts";
124
125
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "electron-effect-rpc",
3
- "version": "0.2.0",
3
+ "version": "0.3.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
  },