electron-json-rpc 1.0.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +978 -0
  3. package/README.zh-CN.md +978 -0
  4. package/dist/debug.d.mts +92 -0
  5. package/dist/debug.d.mts.map +1 -0
  6. package/dist/debug.mjs +206 -0
  7. package/dist/debug.mjs.map +1 -0
  8. package/dist/error-xVRu7Lxq.mjs +131 -0
  9. package/dist/error-xVRu7Lxq.mjs.map +1 -0
  10. package/dist/event.d.mts +71 -0
  11. package/dist/event.d.mts.map +1 -0
  12. package/dist/event.mjs +60 -0
  13. package/dist/event.mjs.map +1 -0
  14. package/dist/index.d.mts +78 -0
  15. package/dist/index.d.mts.map +1 -0
  16. package/dist/index.mjs +4 -0
  17. package/dist/internal-BZK_0O3n.mjs +23 -0
  18. package/dist/internal-BZK_0O3n.mjs.map +1 -0
  19. package/dist/main.d.mts +151 -0
  20. package/dist/main.d.mts.map +1 -0
  21. package/dist/main.mjs +329 -0
  22. package/dist/main.mjs.map +1 -0
  23. package/dist/preload.d.mts +23 -0
  24. package/dist/preload.d.mts.map +1 -0
  25. package/dist/preload.mjs +417 -0
  26. package/dist/preload.mjs.map +1 -0
  27. package/dist/renderer/builder.d.mts +64 -0
  28. package/dist/renderer/builder.d.mts.map +1 -0
  29. package/dist/renderer/builder.mjs +101 -0
  30. package/dist/renderer/builder.mjs.map +1 -0
  31. package/dist/renderer/client.d.mts +42 -0
  32. package/dist/renderer/client.d.mts.map +1 -0
  33. package/dist/renderer/client.mjs +136 -0
  34. package/dist/renderer/client.mjs.map +1 -0
  35. package/dist/renderer/event.d.mts +17 -0
  36. package/dist/renderer/event.d.mts.map +1 -0
  37. package/dist/renderer/event.mjs +117 -0
  38. package/dist/renderer/event.mjs.map +1 -0
  39. package/dist/renderer/index.d.mts +6 -0
  40. package/dist/renderer/index.mjs +6 -0
  41. package/dist/stream.d.mts +38 -0
  42. package/dist/stream.d.mts.map +1 -0
  43. package/dist/stream.mjs +80 -0
  44. package/dist/stream.mjs.map +1 -0
  45. package/dist/types-BnGse9DF.d.mts +201 -0
  46. package/dist/types-BnGse9DF.d.mts.map +1 -0
  47. package/package.json +92 -0
@@ -0,0 +1,78 @@
1
+ import { S as UnderlyingSource, _ as RpcValidator, a as ExposeRpcApiOptions, b as StreamMethodOptions, c as JsonRpcRequest, d as RpcClientOptions, f as RpcDebugOptions, g as RpcMethodOptions, h as RpcLogger, i as EventSubscriber, l as JsonRpcResponse, m as RpcLogEntry, n as EventBusEvents, o as JsonRpcError, p as RpcHandler, r as EventHandler, s as JsonRpcErrorCode, t as EventBus, u as RpcApi, v as StreamChunk, x as StreamRequest, y as StreamHandler } from "./types-BnGse9DF.mjs";
2
+ import { STREAM_CHANNEL, asyncGeneratorToStream, createStreamChunk, generateStreamId, isReadableStream, iterableToStream, readStream } from "./stream.mjs";
3
+
4
+ //#region src/error.d.ts
5
+ /**
6
+ * Create a JSON-RPC error object
7
+ */
8
+ declare function createJsonRpcError(code: number, message: string, data?: unknown): JsonRpcError;
9
+ /**
10
+ * Predefined error creators
11
+ */
12
+ declare const errors: {
13
+ parseError: (data?: unknown) => JsonRpcError;
14
+ invalidRequest: (data?: unknown) => JsonRpcError;
15
+ methodNotFound: (method?: string) => JsonRpcError;
16
+ invalidParams: (data?: unknown) => JsonRpcError;
17
+ internalError: (data?: unknown) => JsonRpcError;
18
+ };
19
+ /**
20
+ * Check if an error is a JSON-RPC error
21
+ */
22
+ declare function isJsonRpcError(error: unknown): error is JsonRpcError;
23
+ /**
24
+ * Convert an Error object to JSON-RPC error
25
+ */
26
+ declare function errorToJsonRpc(error: unknown): JsonRpcError;
27
+ /**
28
+ * Timeout error class
29
+ */
30
+ declare class RpcTimeoutError extends Error {
31
+ readonly name: "RpcTimeoutError";
32
+ readonly timeout: number;
33
+ constructor(timeout: number);
34
+ }
35
+ /**
36
+ * Check if an error is a timeout error
37
+ */
38
+ declare function isTimeoutError(error: unknown): error is RpcTimeoutError;
39
+ /**
40
+ * Error thrown when queue is full and fullBehavior is 'reject'
41
+ */
42
+ declare class RpcQueueFullError extends Error {
43
+ readonly name: "RpcQueueFullError";
44
+ readonly currentSize: number;
45
+ readonly maxSize: number;
46
+ constructor(currentSize: number, maxSize: number);
47
+ }
48
+ /**
49
+ * Error thrown when connection to main process is lost
50
+ */
51
+ declare class RpcConnectionError extends Error {
52
+ readonly name: "RpcConnectionError";
53
+ readonly code?: string;
54
+ constructor(message: string, code?: string);
55
+ }
56
+ /**
57
+ * Error thrown when request is evicted from queue
58
+ */
59
+ declare class RpcQueueEvictedError extends Error {
60
+ readonly name: "RpcQueueEvictedError";
61
+ readonly reason: "full" | "timeout";
62
+ constructor(reason: "full" | "timeout");
63
+ }
64
+ /**
65
+ * Check if an error is a queue full error
66
+ */
67
+ declare function isQueueFullError(error: unknown): error is RpcQueueFullError;
68
+ /**
69
+ * Check if an error is a connection error
70
+ */
71
+ declare function isConnectionError(error: unknown): error is RpcConnectionError;
72
+ /**
73
+ * Check if an error is a queue evicted error
74
+ */
75
+ declare function isQueueEvictedError(error: unknown): error is RpcQueueEvictedError;
76
+ //#endregion
77
+ export { EventBus, EventBusEvents, EventHandler, EventSubscriber, ExposeRpcApiOptions, JsonRpcError, JsonRpcErrorCode, JsonRpcRequest, JsonRpcResponse, RpcApi, RpcClientOptions, RpcConnectionError, RpcDebugOptions, RpcHandler, RpcLogEntry, RpcLogger, RpcMethodOptions, RpcQueueEvictedError, RpcQueueFullError, RpcTimeoutError, RpcValidator, STREAM_CHANNEL, StreamChunk, StreamHandler, StreamMethodOptions, StreamRequest, UnderlyingSource, asyncGeneratorToStream, createJsonRpcError, createStreamChunk, errorToJsonRpc, errors, generateStreamId, isConnectionError, isJsonRpcError, isQueueEvictedError, isQueueFullError, isReadableStream, isTimeoutError, iterableToStream, readStream };
78
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/error.ts"],"mappings":";;;;;AAUA;AAOA;iBAPgB,kBAAA,CAAA,IAAA,UAAA,OAAA,UAAA,IAAA,aAAmE,YAAA;AAAA;AAOnF;;AAPmF,cAOtE,MAAA;EAAA,UAAA,GAAA,IAAA,eACgB,YAAA;EAAA,cAAA,GAAA,IAAA,eAEI,YAAA;EAAA,cAAA,GAAA,MAAA,cAEC,YAAA;EAAA,aAAA,GAAA,IAAA,eAKF,YAAA;EAAA,aAAA,GAAA,IAAA,eAEA,YAAA;AAAA;AAAA;;AAOhC;AAPgC,iBAOhB,cAAA,CAAA,KAAA,YAAA,KAAA,IAAyC,YAAA;AAAA;AAczD;AAuBA;AArCyD,iBAczC,cAAA,CAAA,KAAA,YAAgC,YAAA;AAAA;AAuBhD;AAcA;AArCgD,cAuBnC,eAAA,SAAwB,KAAA;EAAA,SAAA,IAAA;EAAA,SAAA,OAAA;EAAA,YAAA,OAAA;AAAA;AAAA;AAcrC;AAOA;AArBqC,iBAcrB,cAAA,CAAA,KAAA,YAAA,KAAA,IAAyC,eAAA;AAAA;AAOzD;AAgBA;AAvByD,cAO5C,iBAAA,SAA0B,KAAA;EAAA,SAAA,IAAA;EAAA,SAAA,WAAA;EAAA,SAAA,OAAA;EAAA,YAAA,WAAA,UAAA,OAAA;AAAA;AAAA;AAgBvC;AAcA;AA9BuC,cAgB1B,kBAAA,SAA2B,KAAA;EAAA,SAAA,IAAA;EAAA,SAAA,IAAA;EAAA,YAAA,OAAA,UAAA,IAAA;AAAA;AAAA;AAcxC;AAcA;AA5BwC,cAc3B,oBAAA,SAA6B,KAAA;EAAA,SAAA,IAAA;EAAA,SAAA,MAAA;EAAA,YAAA,MAAA;AAAA;AAAA;AAc1C;AAOA;AArB0C,iBAc1B,gBAAA,CAAA,KAAA,YAAA,KAAA,IAA2C,iBAAA;AAAA;AAO3D;AAOA;AAd2D,iBAO3C,iBAAA,CAAA,KAAA,YAAA,KAAA,IAA4C,kBAAA;AAAA;AAO5D;;AAP4D,iBAO5C,mBAAA,CAAA,KAAA,YAAA,KAAA,IAA8C,oBAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { a as createJsonRpcError, c as isConnectionError, d as isQueueFullError, f as isTimeoutError, i as RpcTimeoutError, l as isJsonRpcError, n as RpcQueueEvictedError, o as errorToJsonRpc, p as JsonRpcErrorCode, r as RpcQueueFullError, s as errors, t as RpcConnectionError, u as isQueueEvictedError } from "./error-xVRu7Lxq.mjs";
2
+ import { STREAM_CHANNEL, asyncGeneratorToStream, createStreamChunk, generateStreamId, isReadableStream, iterableToStream, readStream } from "./stream.mjs";
3
+
4
+ export { JsonRpcErrorCode, RpcConnectionError, RpcQueueEvictedError, RpcQueueFullError, RpcTimeoutError, STREAM_CHANNEL, asyncGeneratorToStream, createJsonRpcError, createStreamChunk, errorToJsonRpc, errors, generateStreamId, isConnectionError, isJsonRpcError, isQueueEvictedError, isQueueFullError, isReadableStream, isTimeoutError, iterableToStream, readStream };
@@ -0,0 +1,23 @@
1
+ import { createDebugTracker, isDebugEnabled } from "./debug.mjs";
2
+
3
+ //#region src/renderer/internal.ts
4
+ /**
5
+ * Default API name exposed by preload
6
+ */
7
+ const DEFAULT_API_NAME = "rpc";
8
+ /**
9
+ * Get the exposed API from window object
10
+ */
11
+ function getExposedApi(apiName) {
12
+ return window[apiName] ?? null;
13
+ }
14
+ /**
15
+ * Create debug tracker with optional logger
16
+ */
17
+ function createTracker(debug, logger) {
18
+ return createDebugTracker(isDebugEnabled(debug), logger ?? (() => {}));
19
+ }
20
+
21
+ //#endregion
22
+ export { createTracker as n, getExposedApi as r, DEFAULT_API_NAME as t };
23
+ //# sourceMappingURL=internal-BZK_0O3n.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-BZK_0O3n.mjs","names":[],"sources":["../src/renderer/internal.ts"],"sourcesContent":["/**\n * Internal utilities for renderer modules\n */\n\nimport type { RpcLogger } from \"../types.js\";\nimport { isDebugEnabled, createDebugTracker, type DebugTracker } from \"../debug.js\";\n\n/**\n * Default API name exposed by preload\n */\nexport const DEFAULT_API_NAME = \"rpc\";\n\n/**\n * Preload API type\n */\nexport type PreloadApi = {\n call: (method: string, ...params: unknown[]) => Promise<unknown>;\n notify: (method: string, ...params: unknown[]) => void;\n stream: (method: string, ...params: unknown[]) => ReadableStream;\n on?: (eventName: string, callback: (data?: unknown) => void) => () => void;\n off?: (eventName: string, callback?: (data?: unknown) => void) => void;\n once?: (eventName: string, callback: (data?: unknown) => void) => void;\n proxy?: <T>(methodNames?: (keyof T)[]) => T;\n};\n\n/**\n * Get the exposed API from window object\n */\nexport function getExposedApi(apiName: string): PreloadApi | null {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const win = window as any;\n return win[apiName] ?? null;\n}\n\n/**\n * Create debug tracker with optional logger\n */\nexport function createTracker(\n debug: boolean | undefined,\n logger: RpcLogger | undefined,\n): DebugTracker {\n const enabled = isDebugEnabled(debug);\n return createDebugTracker(enabled, logger ?? (() => {}));\n}\n"],"mappings":";;;;;;AAUA,MAAa,mBAAmB;;;;AAkBhC,SAAgB,cAAc,SAAoC;AAGhE,QADY,OACD,YAAY;;;;;AAMzB,SAAgB,cACd,OACA,QACc;AAEd,QAAO,mBADS,eAAe,MAAM,EACF,iBAAiB,IAAI"}
@@ -0,0 +1,151 @@
1
+ import { g as RpcMethodOptions, p as RpcHandler, y as StreamHandler } from "./types-BnGse9DF.mjs";
2
+
3
+ //#region src/main.d.ts
4
+ /**
5
+ * JSON-RPC Server for Electron Main Process
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { app, BrowserWindow } from 'electron';
10
+ * import { RpcServer } from 'electron-json-rpc/main';
11
+ *
12
+ * const rpc = new RpcServer();
13
+ *
14
+ * rpc.register('add', (a: number, b: number) => a + b);
15
+ * rpc.register('fetchData', async (url: string) => {
16
+ * const response = await fetch(url);
17
+ * return response.json();
18
+ * });
19
+ * ```
20
+ */
21
+ declare class RpcServer {
22
+ private readonly methods;
23
+ private readonly streams;
24
+ private readonly eventSubscribers;
25
+ private readonly handleMessageBound;
26
+ private readonly handleStreamMessageBound;
27
+ private readonly handleEventBusMessageBound;
28
+ private ipcMain;
29
+ private webContents;
30
+ private isListening;
31
+ constructor(
32
+ /**
33
+ * Electron instance (for dependency injection in testing)
34
+ * @internal
35
+ */
36
+ electron?: {
37
+ ipcMain: any;
38
+ webContents: any;
39
+ });
40
+ /**
41
+ * Register a RPC method
42
+ * @param name - Method name
43
+ * @param handler - Handler function
44
+ * @param options - Optional validation and metadata
45
+ */
46
+ register(name: string, handler: RpcHandler, options?: RpcMethodOptions): void;
47
+ /**
48
+ * Register a stream method that returns a ReadableStream
49
+ * @param name - Method name
50
+ * @param handler - Handler function that returns a ReadableStream
51
+ * @param options - Optional validation and metadata
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * rpc.registerStream('dataStream', (count: number) => {
56
+ * return new ReadableStream({
57
+ * async start(controller) {
58
+ * for (let i = 0; i < count; i++) {
59
+ * controller.enqueue({ index: i, data: `chunk ${i}` });
60
+ * await new Promise(r => setTimeout(r, 100));
61
+ * }
62
+ * controller.close();
63
+ * }
64
+ * });
65
+ * });
66
+ * ```
67
+ */
68
+ registerStream(name: string, handler: StreamHandler, options?: RpcMethodOptions): void;
69
+ /**
70
+ * Unregister a RPC method
71
+ */
72
+ unregister(name: string): void;
73
+ /**
74
+ * Check if a method is registered
75
+ */
76
+ has(name: string): boolean;
77
+ /**
78
+ * Get all registered method names
79
+ */
80
+ getMethodNames(): string[];
81
+ /**
82
+ * Start listening for IPC messages
83
+ */
84
+ listen(): void;
85
+ /**
86
+ * Stop listening for IPC messages
87
+ */
88
+ dispose(): void;
89
+ /**
90
+ * Handle incoming IPC message
91
+ */
92
+ private handleMessage;
93
+ /**
94
+ * Handle stream-related messages from renderer
95
+ */
96
+ private handleStreamMessage;
97
+ /**
98
+ * Process a single request and return response
99
+ */
100
+ private processRequest;
101
+ /**
102
+ * Handle a stream method request
103
+ * Returns stream ID and starts streaming in background
104
+ */
105
+ private handleStreamRequest;
106
+ /**
107
+ * Execute a stream handler and send chunks to renderer
108
+ */
109
+ private executeStreamHandler;
110
+ /**
111
+ * Handle event bus messages (subscribe/unsubscribe)
112
+ */
113
+ private handleEventBusMessage;
114
+ /**
115
+ * Subscribe a window to an event
116
+ */
117
+ private subscribeToEvent;
118
+ /**
119
+ * Unsubscribe a window from an event
120
+ */
121
+ private unsubscribeFromEvent;
122
+ /**
123
+ * Publish an event to all subscribed windows
124
+ * @param eventName - The name of the event to publish
125
+ * @param data - Optional data to send with the event
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * rpc.publish('user-updated', { id: '123', name: 'John' });
130
+ * ```
131
+ */
132
+ publish(eventName: string, data?: unknown): void;
133
+ /**
134
+ * Get current event subscribers
135
+ * @returns Record mapping event names to subscriber counts
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const subscribers = rpc.getEventSubscribers();
140
+ * console.log(subscribers); // { 'user-updated': 2, 'data-changed': 1 }
141
+ * ```
142
+ */
143
+ getEventSubscribers(): Record<string, number>;
144
+ }
145
+ /**
146
+ * Create a new RPC server instance
147
+ */
148
+ declare function createRpcServer(): RpcServer;
149
+ //#endregion
150
+ export { RpcServer, createRpcServer };
151
+ //# sourceMappingURL=main.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.mts","names":[],"sources":["../src/main.ts"],"mappings":";;;;AA2DA;;;;;;;AAibA;;;;;;;;;cAjba,SAAA;EAAA,iBAAA,OAAA;EAAA,iBAAA,OAAA;EAAA,iBAAA,gBAAA;EAAA,iBAAA,kBAAA;EAAA,iBAAA,wBAAA;EAAA,iBAAA,0BAAA;EAAA,QAAA,OAAA;EAAA,QAAA,WAAA;EAAA,QAAA,WAAA;EAAA;EAAA;;;;EAAA,QAAA;IAAA,OAAA;IAAA,WAAA;EAAA;EAAA;;;;;;EAAA,SAAA,IAAA,UAAA,OAAA,EAmDqB,UAAA,EAAA,OAAA,GAAsB,gBAAA;EAAA;;;;;AA8XxD;;;;;;;;;;;;;;;;EA9XwD,eAAA,IAAA,UAAA,OAAA,EA6BhB,aAAA,EAAA,OAAA,GAAyB,gBAAA;EAAA;;;EAAA,WAAA,IAAA;EAAA;;;EAAA,IAAA,IAAA;EAAA;;;EAAA,eAAA;EAAA;;;EAAA,OAAA;EAAA;;;EAAA,QAAA;EAAA;;;EAAA,QAAA,aAAA;EAAA;;;EAAA,QAAA,mBAAA;EAAA;;;EAAA,QAAA,cAAA;EAAA;;;AAiWjE;EAjWiE,QAAA,mBAAA;EAAA;;;EAAA,QAAA,oBAAA;EAAA;;;EAAA,QAAA,qBAAA;EAAA;;;EAAA,QAAA,gBAAA;EAAA;;;EAAA,QAAA,oBAAA;EAAA;;;AAiWjE;;;;;;;EAjWiE,QAAA,SAAA,UAAA,IAAA;EAAA;;;AAiWjE;;;;;;;EAjWiE,oBAAA,GAqVxC,MAAA;AAAA;AAAA;;AAYzB;AAZyB,iBAYT,eAAA,CAAA,GAAmB,SAAA"}
package/dist/main.mjs ADDED
@@ -0,0 +1,329 @@
1
+ import { o as errorToJsonRpc, s as errors } from "./error-xVRu7Lxq.mjs";
2
+ import { STREAM_CHANNEL, createStreamChunk, generateStreamId } from "./stream.mjs";
3
+ import { EVENT_CHANNEL } from "./event.mjs";
4
+ import { createRequire } from "node:module";
5
+
6
+ //#region rolldown:runtime
7
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
8
+
9
+ //#endregion
10
+ //#region src/main.ts
11
+ /**
12
+ * IPC channel name for JSON-RPC communication
13
+ */
14
+ const RPC_CHANNEL = "json-rpc";
15
+ const HEALTH_CHECK_METHOD = "__rpc_health__";
16
+ /**
17
+ * JSON-RPC Server for Electron Main Process
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { app, BrowserWindow } from 'electron';
22
+ * import { RpcServer } from 'electron-json-rpc/main';
23
+ *
24
+ * const rpc = new RpcServer();
25
+ *
26
+ * rpc.register('add', (a: number, b: number) => a + b);
27
+ * rpc.register('fetchData', async (url: string) => {
28
+ * const response = await fetch(url);
29
+ * return response.json();
30
+ * });
31
+ * ```
32
+ */
33
+ var RpcServer = class {
34
+ methods = /* @__PURE__ */ new Map();
35
+ streams = /* @__PURE__ */ new Map();
36
+ eventSubscribers = /* @__PURE__ */ new Map();
37
+ handleMessageBound;
38
+ handleStreamMessageBound;
39
+ handleEventBusMessageBound;
40
+ ipcMain;
41
+ webContents;
42
+ isListening = false;
43
+ constructor(electron) {
44
+ try {
45
+ const e = electron || __require("electron");
46
+ this.ipcMain = e.ipcMain;
47
+ this.webContents = e.webContents;
48
+ } catch {
49
+ throw new Error("Electron not found. Please install electron as a peer dependency.");
50
+ }
51
+ this.handleMessageBound = this.handleMessage.bind(this);
52
+ this.handleStreamMessageBound = this.handleStreamMessage.bind(this);
53
+ this.handleEventBusMessageBound = this.handleEventBusMessage.bind(this);
54
+ if (!this.methods.has(HEALTH_CHECK_METHOD)) this.register(HEALTH_CHECK_METHOD, () => true);
55
+ }
56
+ /**
57
+ * Register a RPC method
58
+ * @param name - Method name
59
+ * @param handler - Handler function
60
+ * @param options - Optional validation and metadata
61
+ */
62
+ register(name, handler, options) {
63
+ this.methods.set(name, {
64
+ handler,
65
+ validate: options?.validate,
66
+ description: options?.description
67
+ });
68
+ }
69
+ /**
70
+ * Register a stream method that returns a ReadableStream
71
+ * @param name - Method name
72
+ * @param handler - Handler function that returns a ReadableStream
73
+ * @param options - Optional validation and metadata
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * rpc.registerStream('dataStream', (count: number) => {
78
+ * return new ReadableStream({
79
+ * async start(controller) {
80
+ * for (let i = 0; i < count; i++) {
81
+ * controller.enqueue({ index: i, data: `chunk ${i}` });
82
+ * await new Promise(r => setTimeout(r, 100));
83
+ * }
84
+ * controller.close();
85
+ * }
86
+ * });
87
+ * });
88
+ * ```
89
+ */
90
+ registerStream(name, handler, options) {
91
+ this.methods.set(name, {
92
+ handler,
93
+ validate: options?.validate,
94
+ description: options?.description,
95
+ isStream: true
96
+ });
97
+ }
98
+ /**
99
+ * Unregister a RPC method
100
+ */
101
+ unregister(name) {
102
+ this.methods.delete(name);
103
+ }
104
+ /**
105
+ * Check if a method is registered
106
+ */
107
+ has(name) {
108
+ return this.methods.has(name);
109
+ }
110
+ /**
111
+ * Get all registered method names
112
+ */
113
+ getMethodNames() {
114
+ return Array.from(this.methods.keys());
115
+ }
116
+ /**
117
+ * Start listening for IPC messages
118
+ */
119
+ listen() {
120
+ if (this.isListening) return;
121
+ this.ipcMain.on(RPC_CHANNEL, this.handleMessageBound);
122
+ this.ipcMain.on(STREAM_CHANNEL, this.handleStreamMessageBound);
123
+ this.ipcMain.on(EVENT_CHANNEL, this.handleEventBusMessageBound);
124
+ this.isListening = true;
125
+ }
126
+ /**
127
+ * Stop listening for IPC messages
128
+ */
129
+ dispose() {
130
+ if (!this.isListening) return;
131
+ this.ipcMain.removeListener(RPC_CHANNEL, this.handleMessageBound);
132
+ this.ipcMain.removeListener(STREAM_CHANNEL, this.handleStreamMessageBound);
133
+ this.ipcMain.removeListener(EVENT_CHANNEL, this.handleEventBusMessageBound);
134
+ this.isListening = false;
135
+ this.methods.clear();
136
+ this.streams.clear();
137
+ this.eventSubscribers.clear();
138
+ }
139
+ /**
140
+ * Handle incoming IPC message
141
+ */
142
+ async handleMessage(_event, request) {
143
+ const sender = _event.sender;
144
+ const response = await this.processRequest(request, sender);
145
+ if (request.id !== void 0 && request.id !== null) _event.reply?.(RPC_CHANNEL, response);
146
+ }
147
+ /**
148
+ * Handle stream-related messages from renderer
149
+ */
150
+ handleStreamMessage(_event, chunk) {
151
+ const { streamId, type } = chunk;
152
+ if (type === "end" || type === "error") this.streams.delete(String(streamId));
153
+ }
154
+ /**
155
+ * Process a single request and return response
156
+ */
157
+ async processRequest(request, sender) {
158
+ const { id, method, params } = request;
159
+ if (!method || typeof method !== "string") return {
160
+ jsonrpc: "2.0",
161
+ id: id ?? null,
162
+ error: errors.invalidRequest()
163
+ };
164
+ const storedMethod = this.methods.get(method);
165
+ if (!storedMethod) return {
166
+ jsonrpc: "2.0",
167
+ id: id ?? null,
168
+ error: errors.methodNotFound(method)
169
+ };
170
+ try {
171
+ let args;
172
+ if (params === void 0) args = [];
173
+ else if (Array.isArray(params)) args = params;
174
+ else args = [params];
175
+ if (storedMethod.validate) try {
176
+ await storedMethod.validate(args);
177
+ } catch (validationError) {
178
+ return {
179
+ jsonrpc: "2.0",
180
+ id: id ?? null,
181
+ error: errors.invalidParams(validationError instanceof Error ? validationError.message : void 0)
182
+ };
183
+ }
184
+ if (storedMethod.isStream) return this.handleStreamRequest(id, method, args, storedMethod, sender);
185
+ const result = await storedMethod.handler(...args);
186
+ return {
187
+ jsonrpc: "2.0",
188
+ id: id ?? null,
189
+ result
190
+ };
191
+ } catch (error) {
192
+ return {
193
+ jsonrpc: "2.0",
194
+ id: id ?? null,
195
+ error: errorToJsonRpc(error)
196
+ };
197
+ }
198
+ }
199
+ /**
200
+ * Handle a stream method request
201
+ * Returns stream ID and starts streaming in background
202
+ */
203
+ async handleStreamRequest(id, _method, args, storedMethod, sender) {
204
+ const streamId = generateStreamId();
205
+ const sendChunk = sender ? (channel, data) => sender.send(channel, data) : (channel, data) => {
206
+ const allWindows = this.webContents.getAllWebContents();
207
+ for (const wc of allWindows) wc.send(channel, data);
208
+ };
209
+ this.streams.set(streamId, {
210
+ streamId,
211
+ sender: sendChunk
212
+ });
213
+ this.executeStreamHandler(streamId, storedMethod.handler, args, sendChunk).catch((error) => {
214
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "error", errorToJsonRpc(error)));
215
+ this.streams.delete(streamId);
216
+ });
217
+ return {
218
+ jsonrpc: "2.0",
219
+ id: id ?? null,
220
+ result: { streamId }
221
+ };
222
+ }
223
+ /**
224
+ * Execute a stream handler and send chunks to renderer
225
+ */
226
+ async executeStreamHandler(streamId, handler, args, sendChunk) {
227
+ const result = await handler(...args);
228
+ if (result instanceof ReadableStream) {
229
+ const reader = result.getReader();
230
+ try {
231
+ while (true) {
232
+ const { done, value } = await reader.read();
233
+ if (done) break;
234
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "chunk", value));
235
+ }
236
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "end"));
237
+ } catch (error) {
238
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "error", errorToJsonRpc(error)));
239
+ } finally {
240
+ reader.releaseLock();
241
+ this.streams.delete(streamId);
242
+ }
243
+ } else {
244
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "chunk", result));
245
+ sendChunk(STREAM_CHANNEL, createStreamChunk(streamId, "end"));
246
+ this.streams.delete(streamId);
247
+ }
248
+ }
249
+ /**
250
+ * Handle event bus messages (subscribe/unsubscribe)
251
+ */
252
+ handleEventBusMessage(_event, message) {
253
+ const { type, eventName } = message;
254
+ const sender = _event.sender;
255
+ if (!sender) return;
256
+ const windowId = sender.id;
257
+ switch (type) {
258
+ case "subscribe":
259
+ this.subscribeToEvent(eventName, windowId);
260
+ break;
261
+ case "unsubscribe":
262
+ this.unsubscribeFromEvent(eventName, windowId);
263
+ break;
264
+ }
265
+ }
266
+ /**
267
+ * Subscribe a window to an event
268
+ */
269
+ subscribeToEvent(eventName, windowId) {
270
+ if (!this.eventSubscribers.has(eventName)) this.eventSubscribers.set(eventName, /* @__PURE__ */ new Set());
271
+ this.eventSubscribers.get(eventName).add(windowId);
272
+ }
273
+ /**
274
+ * Unsubscribe a window from an event
275
+ */
276
+ unsubscribeFromEvent(eventName, windowId) {
277
+ const subscribers = this.eventSubscribers.get(eventName);
278
+ if (subscribers) {
279
+ subscribers.delete(windowId);
280
+ if (subscribers.size === 0) this.eventSubscribers.delete(eventName);
281
+ }
282
+ }
283
+ /**
284
+ * Publish an event to all subscribed windows
285
+ * @param eventName - The name of the event to publish
286
+ * @param data - Optional data to send with the event
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * rpc.publish('user-updated', { id: '123', name: 'John' });
291
+ * ```
292
+ */
293
+ publish(eventName, data) {
294
+ const subscribers = this.eventSubscribers.get(eventName);
295
+ if (!subscribers || subscribers.size === 0) return;
296
+ const message = {
297
+ type: "event",
298
+ eventName,
299
+ data
300
+ };
301
+ const allWindows = this.webContents.getAllWebContents();
302
+ for (const wc of allWindows) if (subscribers.has(wc.id)) wc.send(EVENT_CHANNEL, message);
303
+ }
304
+ /**
305
+ * Get current event subscribers
306
+ * @returns Record mapping event names to subscriber counts
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * const subscribers = rpc.getEventSubscribers();
311
+ * console.log(subscribers); // { 'user-updated': 2, 'data-changed': 1 }
312
+ * ```
313
+ */
314
+ getEventSubscribers() {
315
+ const result = {};
316
+ for (const [eventName, subscribers] of this.eventSubscribers.entries()) result[eventName] = subscribers.size;
317
+ return result;
318
+ }
319
+ };
320
+ /**
321
+ * Create a new RPC server instance
322
+ */
323
+ function createRpcServer() {
324
+ return new RpcServer();
325
+ }
326
+
327
+ //#endregion
328
+ export { RpcServer, createRpcServer };
329
+ //# sourceMappingURL=main.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.mjs","names":[],"sources":["../src/main.ts"],"sourcesContent":["/**\n * JSON-RPC Server for Electron Main Process\n */\n\nimport type {\n JsonRpcRequest,\n JsonRpcResponse,\n RpcHandler,\n RpcMethodOptions,\n RpcValidator,\n StreamHandler,\n StreamChunk,\n} from \"./types.js\";\nimport { errors, errorToJsonRpc } from \"./error.js\";\nimport { generateStreamId, createStreamChunk, STREAM_CHANNEL } from \"./stream.js\";\nimport { EVENT_CHANNEL, type EventMessage } from \"./event.js\";\n\n/**\n * Stored method with metadata\n */\ninterface StoredMethod {\n handler: RpcHandler;\n validate?: RpcValidator;\n description?: string;\n isStream?: boolean;\n}\n\n/**\n * Active stream state\n */\ninterface ActiveStream {\n streamId: string;\n sender: (channel: string, data: unknown) => void;\n}\n\n/**\n * IPC channel name for JSON-RPC communication\n */\nconst RPC_CHANNEL = \"json-rpc\";\n\nconst HEALTH_CHECK_METHOD = \"__rpc_health__\";\n\n/**\n * JSON-RPC Server for Electron Main Process\n *\n * @example\n * ```typescript\n * import { app, BrowserWindow } from 'electron';\n * import { RpcServer } from 'electron-json-rpc/main';\n *\n * const rpc = new RpcServer();\n *\n * rpc.register('add', (a: number, b: number) => a + b);\n * rpc.register('fetchData', async (url: string) => {\n * const response = await fetch(url);\n * return response.json();\n * });\n * ```\n */\nexport class RpcServer {\n private readonly methods = new Map<string, StoredMethod>();\n private readonly streams = new Map<string, ActiveStream>();\n private readonly eventSubscribers = new Map<string, Set<number>>(); // eventName -> Set of window IDs\n private readonly handleMessageBound: (event: unknown, request: JsonRpcRequest) => void;\n private readonly handleStreamMessageBound: (event: unknown, chunk: StreamChunk) => void;\n private readonly handleEventBusMessageBound: (event: unknown, message: EventMessage) => void;\n private ipcMain: any;\n private webContents: any;\n private isListening = false;\n\n constructor(\n /**\n * Electron instance (for dependency injection in testing)\n * @internal\n */\n electron?: {\n ipcMain: any;\n webContents: any;\n },\n ) {\n // Electron is a peer dependency, we'll get it at runtime\n // Or use provided instance (for testing)\n try {\n const e =\n electron ||\n (() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(\"electron\");\n })();\n this.ipcMain = e.ipcMain;\n this.webContents = e.webContents;\n } catch {\n throw new Error(\"Electron not found. Please install electron as a peer dependency.\");\n }\n\n this.handleMessageBound = this.handleMessage.bind(this);\n this.handleStreamMessageBound = this.handleStreamMessage.bind(this);\n this.handleEventBusMessageBound = this.handleEventBusMessage.bind(this);\n\n if (!this.methods.has(HEALTH_CHECK_METHOD)) {\n this.register(HEALTH_CHECK_METHOD, () => true);\n }\n }\n\n /**\n * Register a RPC method\n * @param name - Method name\n * @param handler - Handler function\n * @param options - Optional validation and metadata\n */\n register(name: string, handler: RpcHandler, options?: RpcMethodOptions): void {\n this.methods.set(name, {\n handler,\n validate: options?.validate,\n description: options?.description,\n });\n }\n\n /**\n * Register a stream method that returns a ReadableStream\n * @param name - Method name\n * @param handler - Handler function that returns a ReadableStream\n * @param options - Optional validation and metadata\n *\n * @example\n * ```typescript\n * rpc.registerStream('dataStream', (count: number) => {\n * return new ReadableStream({\n * async start(controller) {\n * for (let i = 0; i < count; i++) {\n * controller.enqueue({ index: i, data: `chunk ${i}` });\n * await new Promise(r => setTimeout(r, 100));\n * }\n * controller.close();\n * }\n * });\n * });\n * ```\n */\n registerStream(name: string, handler: StreamHandler, options?: RpcMethodOptions): void {\n this.methods.set(name, {\n handler: handler as RpcHandler,\n validate: options?.validate,\n description: options?.description,\n isStream: true,\n });\n }\n\n /**\n * Unregister a RPC method\n */\n unregister(name: string): void {\n this.methods.delete(name);\n }\n\n /**\n * Check if a method is registered\n */\n has(name: string): boolean {\n return this.methods.has(name);\n }\n\n /**\n * Get all registered method names\n */\n getMethodNames(): string[] {\n return Array.from(this.methods.keys());\n }\n\n /**\n * Start listening for IPC messages\n */\n listen(): void {\n if (this.isListening) {\n return;\n }\n\n this.ipcMain.on(RPC_CHANNEL, this.handleMessageBound);\n this.ipcMain.on(STREAM_CHANNEL, this.handleStreamMessageBound);\n this.ipcMain.on(EVENT_CHANNEL, this.handleEventBusMessageBound);\n this.isListening = true;\n }\n\n /**\n * Stop listening for IPC messages\n */\n dispose(): void {\n if (!this.isListening) {\n return;\n }\n\n this.ipcMain.removeListener(RPC_CHANNEL, this.handleMessageBound);\n this.ipcMain.removeListener(STREAM_CHANNEL, this.handleStreamMessageBound);\n this.ipcMain.removeListener(EVENT_CHANNEL, this.handleEventBusMessageBound);\n this.isListening = false;\n this.methods.clear();\n this.streams.clear();\n this.eventSubscribers.clear();\n }\n\n /**\n * Handle incoming IPC message\n */\n private async handleMessage(_event: unknown, request: JsonRpcRequest): Promise<void> {\n const sender = (_event as { sender?: { send: (channel: string, data: unknown) => void } })\n .sender;\n\n const response = await this.processRequest(request, sender);\n\n // Only send response for non-notifications (requests with id)\n if (request.id !== undefined && request.id !== null) {\n // Send response via the same event's reply method\n const event = _event as {\n reply?: (channel: string, data: unknown) => void;\n };\n event.reply?.(RPC_CHANNEL, response);\n }\n }\n\n /**\n * Handle stream-related messages from renderer\n */\n private handleStreamMessage(_event: unknown, chunk: StreamChunk): void {\n const { streamId, type } = chunk;\n\n if (type === \"end\" || type === \"error\") {\n // Clean up stream state\n this.streams.delete(String(streamId));\n }\n }\n\n /**\n * Process a single request and return response\n */\n private async processRequest(\n request: JsonRpcRequest,\n sender?: { send: (channel: string, data: unknown) => void },\n ): Promise<JsonRpcResponse> {\n const { id, method, params } = request;\n\n // Validate request\n if (!method || typeof method !== \"string\") {\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n error: errors.invalidRequest(),\n };\n }\n\n // Check if method exists\n const storedMethod = this.methods.get(method);\n if (!storedMethod) {\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n error: errors.methodNotFound(method),\n };\n }\n\n try {\n // Normalize params to array\n let args: unknown[];\n if (params === undefined) {\n args = [];\n } else if (Array.isArray(params)) {\n args = params;\n } else {\n // Named params - pass as single object\n args = [params];\n }\n\n // Run validator if provided\n if (storedMethod.validate) {\n try {\n await storedMethod.validate(args);\n } catch (validationError) {\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n error: errors.invalidParams(\n validationError instanceof Error ? validationError.message : undefined,\n ),\n };\n }\n }\n\n // Handle stream methods\n if (storedMethod.isStream) {\n return this.handleStreamRequest(id, method, args, storedMethod, sender);\n }\n\n // Execute regular handler\n const result = await storedMethod.handler(...args);\n\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n result,\n };\n } catch (error) {\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n error: errorToJsonRpc(error),\n };\n }\n }\n\n /**\n * Handle a stream method request\n * Returns stream ID and starts streaming in background\n */\n private async handleStreamRequest(\n id: string | number | null | undefined,\n _method: string,\n args: unknown[],\n storedMethod: StoredMethod,\n sender?: { send: (channel: string, data: unknown) => void },\n ): Promise<JsonRpcResponse> {\n const streamId = generateStreamId();\n\n // Prefer responding to the requesting sender; fallback to all windows\n const sendChunk = sender\n ? (channel: string, data: unknown) => sender.send(channel, data)\n : (channel: string, data: unknown) => {\n const allWindows = this.webContents.getAllWebContents();\n for (const wc of allWindows) {\n wc.send(channel, data);\n }\n };\n\n this.streams.set(streamId, { streamId, sender: sendChunk });\n\n // Start streaming in background\n this.executeStreamHandler(streamId, storedMethod.handler, args, sendChunk).catch((error) => {\n const errorChunk = createStreamChunk(streamId, \"error\", errorToJsonRpc(error));\n sendChunk(STREAM_CHANNEL, errorChunk);\n this.streams.delete(streamId);\n });\n\n // Return stream ID immediately\n return {\n jsonrpc: \"2.0\",\n id: id ?? null,\n result: { streamId },\n };\n }\n\n /**\n * Execute a stream handler and send chunks to renderer\n */\n private async executeStreamHandler(\n streamId: string,\n handler: RpcHandler,\n args: unknown[],\n sendChunk: (channel: string, data: unknown) => void,\n ): Promise<void> {\n const result = await handler(...args);\n\n if (result instanceof ReadableStream) {\n const reader = result.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = createStreamChunk(streamId, \"chunk\", value);\n sendChunk(STREAM_CHANNEL, chunk);\n }\n\n // Send end chunk\n const endChunk = createStreamChunk(streamId, \"end\");\n sendChunk(STREAM_CHANNEL, endChunk);\n } catch (error) {\n const errorChunk = createStreamChunk(streamId, \"error\", errorToJsonRpc(error));\n sendChunk(STREAM_CHANNEL, errorChunk);\n } finally {\n reader.releaseLock();\n this.streams.delete(streamId);\n }\n } else {\n // Non-stream result, send as single chunk and end\n const chunk = createStreamChunk(streamId, \"chunk\", result);\n sendChunk(STREAM_CHANNEL, chunk);\n\n const endChunk = createStreamChunk(streamId, \"end\");\n sendChunk(STREAM_CHANNEL, endChunk);\n\n this.streams.delete(streamId);\n }\n }\n\n /**\n * Handle event bus messages (subscribe/unsubscribe)\n */\n private handleEventBusMessage(_event: unknown, message: EventMessage): void {\n const { type, eventName } = message;\n const sender = (_event as { sender?: { id: number } }).sender;\n\n if (!sender) {\n return;\n }\n\n const windowId = sender.id;\n\n switch (type) {\n case \"subscribe\":\n this.subscribeToEvent(eventName, windowId);\n break;\n case \"unsubscribe\":\n this.unsubscribeFromEvent(eventName, windowId);\n break;\n }\n }\n\n /**\n * Subscribe a window to an event\n */\n private subscribeToEvent(eventName: string, windowId: number): void {\n if (!this.eventSubscribers.has(eventName)) {\n this.eventSubscribers.set(eventName, new Set());\n }\n this.eventSubscribers.get(eventName)!.add(windowId);\n }\n\n /**\n * Unsubscribe a window from an event\n */\n private unsubscribeFromEvent(eventName: string, windowId: number): void {\n const subscribers = this.eventSubscribers.get(eventName);\n if (subscribers) {\n subscribers.delete(windowId);\n if (subscribers.size === 0) {\n this.eventSubscribers.delete(eventName);\n }\n }\n }\n\n /**\n * Publish an event to all subscribed windows\n * @param eventName - The name of the event to publish\n * @param data - Optional data to send with the event\n *\n * @example\n * ```typescript\n * rpc.publish('user-updated', { id: '123', name: 'John' });\n * ```\n */\n publish(eventName: string, data?: unknown): void {\n const subscribers = this.eventSubscribers.get(eventName);\n if (!subscribers || subscribers.size === 0) {\n return; // No subscribers, nothing to do\n }\n\n const message: EventMessage = {\n type: \"event\",\n eventName,\n data,\n };\n\n // Send to all subscribed windows\n const allWindows = this.webContents.getAllWebContents();\n for (const wc of allWindows) {\n if (subscribers.has(wc.id)) {\n wc.send(EVENT_CHANNEL, message);\n }\n }\n }\n\n /**\n * Get current event subscribers\n * @returns Record mapping event names to subscriber counts\n *\n * @example\n * ```typescript\n * const subscribers = rpc.getEventSubscribers();\n * console.log(subscribers); // { 'user-updated': 2, 'data-changed': 1 }\n * ```\n */\n getEventSubscribers(): Record<string, number> {\n const result: Record<string, number> = {};\n for (const [eventName, subscribers] of this.eventSubscribers.entries()) {\n result[eventName] = subscribers.size;\n }\n return result;\n }\n}\n\n/**\n * Create a new RPC server instance\n */\nexport function createRpcServer(): RpcServer {\n return new RpcServer();\n}\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { a as ExposeRpcApiOptions } from "./types-BnGse9DF.mjs";
2
+
3
+ //#region src/preload.d.ts
4
+ /**
5
+ * Expose an RPC API to the renderer process via contextBridge
6
+ */
7
+ declare function exposeRpcApi(options: ExposeRpcApiOptions): void;
8
+ /**
9
+ * Create an RPC client for use in preload scripts
10
+ * (without exposing to renderer)
11
+ */
12
+ declare function createPreloadClient(ipcRenderer: ExposeRpcApiOptions["ipcRenderer"], timeout?: number): {
13
+ call: (method: string, ...params: unknown[]) => Promise<unknown>;
14
+ notify: (method: string, ...params: unknown[]) => void;
15
+ stream: (method: string, ...params: unknown[]) => ReadableStream;
16
+ on: (eventName: string, callback: (data?: unknown) => void) => () => void;
17
+ off: (eventName: string, callback?: (data?: unknown) => void) => void;
18
+ once: (eventName: string, callback: (data?: unknown) => void) => void;
19
+ dispose: () => void;
20
+ };
21
+ //#endregion
22
+ export { createPreloadClient, exposeRpcApi };
23
+ //# sourceMappingURL=preload.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.d.mts","names":[],"sources":["../src/preload.ts"],"mappings":";;;;AAkXA;AAoBA;iBApBgB,YAAA,CAAA,OAAA,EAAsB,mBAAA;AAAA;AAoBtC;;;AApBsC,iBAoBtB,mBAAA,CAAA,WAAA,EACD,mBAAA,iBAAA,OAAA;EAAA,IAAA,GAAA,MAAA,aAAA,MAAA,gBAGmC,OAAA;EAAA,MAAA,GAAA,MAAA,aAAA,MAAA;EAAA,MAAA,GAAA,MAAA,aAAA,MAAA,gBAEE,cAAA;EAAA,EAAA,GAAA,SAAA,UAAA,QAAA,GAAA,IAAA;EAAA,GAAA,GAAA,SAAA,UAAA,QAAA,IAAA,IAAA;EAAA,IAAA,GAAA,SAAA,UAAA,QAAA,GAAA,IAAA;EAAA,OAAA;AAAA"}