electron-buff 1.0.3 → 1.0.6
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 +2 -6
- package/dist/packageHelper/main/index.d.mts +31 -0
- package/dist/packageHelper/main/index.d.ts +31 -0
- package/dist/packageHelper/main/index.js +66 -0
- package/dist/packageHelper/main/index.js.map +1 -0
- package/dist/packageHelper/main/index.mjs +64 -0
- package/dist/packageHelper/main/index.mjs.map +1 -0
- package/dist/packageHelper/preload/index.d.mts +18 -0
- package/dist/packageHelper/preload/index.d.ts +18 -0
- package/dist/packageHelper/preload/index.js +30 -0
- package/dist/packageHelper/preload/index.js.map +1 -0
- package/dist/packageHelper/preload/index.mjs +28 -0
- package/dist/packageHelper/preload/index.mjs.map +1 -0
- package/dist/packageHelper/renderer/index.d.mts +21 -0
- package/dist/packageHelper/renderer/index.d.ts +21 -0
- package/dist/packageHelper/renderer/index.js +8 -0
- package/dist/packageHelper/renderer/index.js.map +1 -0
- package/dist/packageHelper/renderer/index.mjs +6 -0
- package/dist/packageHelper/renderer/index.mjs.map +1 -0
- package/dist/pathHelper/preload/index.d.mts +11 -0
- package/dist/pathHelper/preload/index.d.ts +11 -0
- package/dist/pathHelper/preload/index.js +44 -0
- package/dist/pathHelper/preload/index.js.map +1 -0
- package/dist/pathHelper/preload/index.mjs +42 -0
- package/dist/pathHelper/preload/index.mjs.map +1 -0
- package/dist/pathHelper/renderer/index.d.mts +4 -13
- package/dist/pathHelper/renderer/index.d.ts +4 -13
- package/dist/pathHelper/renderer/index.js +2 -35
- package/dist/pathHelper/renderer/index.js.map +1 -1
- package/dist/pathHelper/renderer/index.mjs +2 -34
- package/dist/pathHelper/renderer/index.mjs.map +1 -1
- package/dist/xpc/main/index.d.mts +50 -1
- package/dist/xpc/main/index.d.ts +50 -1
- package/dist/xpc/main/index.js +49 -4
- package/dist/xpc/main/index.js.map +1 -1
- package/dist/xpc/main/index.mjs +48 -5
- package/dist/xpc/main/index.mjs.map +1 -1
- package/dist/xpc/preload/index.d.mts +54 -31
- package/dist/xpc/preload/index.d.ts +54 -31
- package/dist/xpc/preload/index.js +95 -58
- package/dist/xpc/preload/index.js.map +1 -1
- package/dist/xpc/preload/index.mjs +94 -59
- package/dist/xpc/preload/index.mjs.map +1 -1
- package/dist/xpc/renderer/index.d.mts +72 -0
- package/dist/xpc/renderer/index.d.ts +72 -0
- package/dist/xpc/renderer/index.js +53 -0
- package/dist/xpc/renderer/index.js.map +1 -0
- package/dist/xpc/renderer/index.mjs +49 -0
- package/dist/xpc/renderer/index.mjs.map +1 -0
- package/package.json +51 -1
|
@@ -8,43 +8,66 @@ type XpcPayload = {
|
|
|
8
8
|
/** Return data from target process, nullable, defaults to null */
|
|
9
9
|
ret?: any;
|
|
10
10
|
};
|
|
11
|
+
type XpcRendererApi = {
|
|
12
|
+
handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>) => void;
|
|
13
|
+
removeHandle: (handleName: string) => void;
|
|
14
|
+
send: (handleName: string, params?: any) => Promise<any>;
|
|
15
|
+
};
|
|
11
16
|
|
|
12
17
|
type XpcHandler = (payload: XpcPayload) => Promise<any>;
|
|
18
|
+
/** Global handlers map, extracted from XpcRenderer class */
|
|
19
|
+
declare const xpcHandlers: Map<string, XpcHandler>;
|
|
20
|
+
|
|
21
|
+
/** The xpcRenderer API instance */
|
|
22
|
+
declare const xpcRenderer: XpcRendererApi;
|
|
23
|
+
|
|
13
24
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
25
|
+
* Base class for preload-process xpc handlers.
|
|
26
|
+
* Subclass this and define async methods — they will be auto-registered
|
|
27
|
+
* as xpc handlers with channel `xpc:ClassName/methodName`.
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* ```ts
|
|
31
|
+
* class UserTable extends XpcPreloadHandler {
|
|
32
|
+
* async getUserList(params?: any): Promise<any> { ... }
|
|
33
|
+
* }
|
|
34
|
+
* const userTable = new UserTable();
|
|
35
|
+
* // auto-registers handler for 'xpc:UserTable/getUserList'
|
|
36
|
+
* ```
|
|
18
37
|
*/
|
|
19
|
-
declare class
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Register a handleName with the main process and bind a local async handler.
|
|
23
|
-
* When another renderer calls send() with this handleName, xpcCenter will forward
|
|
24
|
-
* the payload to this renderer, the handler executes, and result is sent back via __xpc_finish__.
|
|
25
|
-
*/
|
|
26
|
-
handle(handleName: string, handler: XpcHandler): void;
|
|
27
|
-
/**
|
|
28
|
-
* Remove a registered handler.
|
|
29
|
-
*/
|
|
30
|
-
removeHandle(handleName: string): void;
|
|
31
|
-
/**
|
|
32
|
-
* Send a message to another renderer (or any registered handler) via main process.
|
|
33
|
-
* Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.
|
|
34
|
-
* Returns the ret value from the target handler, or null.
|
|
35
|
-
*/
|
|
36
|
-
send(handleName: string, params?: any): Promise<any>;
|
|
38
|
+
declare class XpcPreloadHandler {
|
|
39
|
+
constructor();
|
|
37
40
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Helper: checks if a function type has at most 1 parameter.
|
|
44
|
+
* Returns the function type itself if valid, `never` otherwise.
|
|
45
|
+
*/
|
|
46
|
+
type AssertSingleParam<F> = F extends () => any ? F : F extends (p: any) => any ? F extends (p: any, q: any, ...rest: any[]) => any ? never : F : never;
|
|
47
|
+
/**
|
|
48
|
+
* Utility type: extracts the method signatures from a handler class,
|
|
49
|
+
* turning each method into an emitter-compatible signature.
|
|
50
|
+
* Methods with 2+ parameters are mapped to `never`, causing a compile error on use.
|
|
51
|
+
*/
|
|
52
|
+
type XpcEmitterOf<T> = {
|
|
53
|
+
[K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: AssertSingleParam<T[K]> extends never ? never : T[K] extends (params: infer P) => any ? (params: P) => Promise<any> : () => Promise<any>;
|
|
43
54
|
};
|
|
55
|
+
|
|
44
56
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
57
|
+
* Create a type-safe emitter proxy for a preload-process xpc handler.
|
|
58
|
+
* The emitter mirrors the handler's method signatures, but each call
|
|
59
|
+
* sends a message via xpcRenderer.send() to `xpc:ClassName/methodName`.
|
|
60
|
+
*
|
|
61
|
+
* Example:
|
|
62
|
+
* ```ts
|
|
63
|
+
* class UserTable extends XpcPreloadHandler {
|
|
64
|
+
* async getUserList(params?: any): Promise<any> { ... }
|
|
65
|
+
* }
|
|
66
|
+
* const userTableEmitter = createXpcPreloadEmitter<UserTable>('UserTable');
|
|
67
|
+
* const list = await userTableEmitter.getUserList({ page: 1 });
|
|
68
|
+
* // sends to 'xpc:UserTable/getUserList'
|
|
69
|
+
* ```
|
|
47
70
|
*/
|
|
48
|
-
declare const
|
|
71
|
+
declare const createXpcPreloadEmitter: <T>(className: string) => XpcEmitterOf<T>;
|
|
49
72
|
|
|
50
|
-
export { type XpcPayload, type XpcRendererApi,
|
|
73
|
+
export { type XpcEmitterOf, type XpcPayload, XpcPreloadHandler, type XpcRendererApi, createXpcPreloadEmitter, xpcHandlers, xpcRenderer };
|
|
@@ -2,87 +2,124 @@
|
|
|
2
2
|
|
|
3
3
|
var electron = require('electron');
|
|
4
4
|
|
|
5
|
-
// src/xpc/preload/
|
|
5
|
+
// src/xpc/preload/xpcPreload.helper.ts
|
|
6
6
|
|
|
7
|
-
// src/xpc/preload/
|
|
7
|
+
// src/xpc/preload/xpcId.helper.ts
|
|
8
8
|
var prefix = Math.random().toString(36).slice(2, 8);
|
|
9
9
|
var counter = 0;
|
|
10
10
|
var generateXpcId = () => {
|
|
11
11
|
return `r-${prefix}-${(++counter).toString(36)}`;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
// src/xpc/preload/
|
|
14
|
+
// src/xpc/preload/xpcPreload.helper.ts
|
|
15
15
|
var XPC_REGISTER = "__xpc_register__";
|
|
16
16
|
var XPC_EXEC = "__xpc_exec__";
|
|
17
17
|
var XPC_FINISH = "__xpc_finish__";
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
electron.ipcRenderer.on(handleName, async (_event, payload) => {
|
|
31
|
-
let ret = null;
|
|
32
|
-
const localHandler = this.handlers.get(handleName);
|
|
33
|
-
if (localHandler) {
|
|
34
|
-
try {
|
|
35
|
-
ret = await localHandler(payload);
|
|
36
|
-
} catch (_e) {
|
|
37
|
-
ret = null;
|
|
38
|
-
}
|
|
18
|
+
var xpcHandlers = /* @__PURE__ */ new Map();
|
|
19
|
+
var handle = (handleName, handler) => {
|
|
20
|
+
xpcHandlers.set(handleName, handler);
|
|
21
|
+
electron.ipcRenderer.send(XPC_REGISTER, { handleName });
|
|
22
|
+
electron.ipcRenderer.on(handleName, async (_event, payload) => {
|
|
23
|
+
let ret = null;
|
|
24
|
+
const localHandler = xpcHandlers.get(handleName);
|
|
25
|
+
if (localHandler) {
|
|
26
|
+
try {
|
|
27
|
+
ret = await localHandler(payload);
|
|
28
|
+
} catch (_e) {
|
|
29
|
+
ret = null;
|
|
39
30
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
}
|
|
32
|
+
electron.ipcRenderer.send(XPC_FINISH, {
|
|
33
|
+
id: payload.id,
|
|
34
|
+
handleName: payload.handleName,
|
|
35
|
+
params: payload.params,
|
|
36
|
+
ret
|
|
46
37
|
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Remove a registered handler.
|
|
50
|
-
*/
|
|
51
|
-
removeHandle(handleName) {
|
|
52
|
-
this.handlers.delete(handleName);
|
|
53
|
-
electron.ipcRenderer.removeAllListeners(handleName);
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Send a message to another renderer (or any registered handler) via main process.
|
|
57
|
-
* Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.
|
|
58
|
-
* Returns the ret value from the target handler, or null.
|
|
59
|
-
*/
|
|
60
|
-
async send(handleName, params) {
|
|
61
|
-
const payload = {
|
|
62
|
-
id: generateXpcId(),
|
|
63
|
-
handleName,
|
|
64
|
-
params,
|
|
65
|
-
ret: null
|
|
66
|
-
};
|
|
67
|
-
return await electron.ipcRenderer.invoke(XPC_EXEC, payload);
|
|
68
|
-
}
|
|
38
|
+
});
|
|
69
39
|
};
|
|
70
|
-
var
|
|
71
|
-
|
|
40
|
+
var removeHandle = (handleName) => {
|
|
41
|
+
xpcHandlers.delete(handleName);
|
|
42
|
+
electron.ipcRenderer.removeAllListeners(handleName);
|
|
43
|
+
};
|
|
44
|
+
var send = async (handleName, params) => {
|
|
45
|
+
const payload = {
|
|
46
|
+
id: generateXpcId(),
|
|
47
|
+
handleName,
|
|
48
|
+
params,
|
|
49
|
+
ret: null
|
|
50
|
+
};
|
|
51
|
+
return await electron.ipcRenderer.invoke(XPC_EXEC, payload);
|
|
52
|
+
};
|
|
53
|
+
var createXpcRendererApi = () => {
|
|
72
54
|
return {
|
|
73
55
|
handle: (handleName, handler) => {
|
|
74
|
-
|
|
56
|
+
handle(handleName, handler);
|
|
75
57
|
},
|
|
76
58
|
removeHandle: (handleName) => {
|
|
77
|
-
|
|
59
|
+
removeHandle(handleName);
|
|
78
60
|
},
|
|
79
61
|
send: (handleName, params) => {
|
|
80
|
-
return
|
|
62
|
+
return send(handleName, params);
|
|
81
63
|
}
|
|
82
64
|
};
|
|
83
65
|
};
|
|
66
|
+
var xpcRenderer = createXpcRendererApi();
|
|
67
|
+
if (process.contextIsolated) {
|
|
68
|
+
try {
|
|
69
|
+
electron.contextBridge.exposeInMainWorld("xpcRenderer", xpcRenderer);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error("[xpcPreload] exposeInMainWorld failed:", error);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
globalThis.xpcRenderer = xpcRenderer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/xpc/shared/xpcHandler.type.ts
|
|
78
|
+
var XPC_HANDLER_PREFIX = "xpc:";
|
|
79
|
+
var buildXpcChannel = (className, methodName) => {
|
|
80
|
+
return `${XPC_HANDLER_PREFIX}${className}/${methodName}`;
|
|
81
|
+
};
|
|
82
|
+
var getHandlerMethodNames = (prototype) => {
|
|
83
|
+
const names = [];
|
|
84
|
+
const keys = Object.getOwnPropertyNames(prototype);
|
|
85
|
+
for (const key of keys) {
|
|
86
|
+
if (key === "constructor") continue;
|
|
87
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
88
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
89
|
+
names.push(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return names;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/xpc/preload/xpcPreload.handler.ts
|
|
96
|
+
var XpcPreloadHandler = class {
|
|
97
|
+
constructor() {
|
|
98
|
+
const className = this.constructor.name;
|
|
99
|
+
const methodNames = getHandlerMethodNames(Object.getPrototypeOf(this));
|
|
100
|
+
for (const methodName of methodNames) {
|
|
101
|
+
const channel = buildXpcChannel(className, methodName);
|
|
102
|
+
const method = this[methodName].bind(this);
|
|
103
|
+
xpcRenderer.handle(channel, async (payload) => {
|
|
104
|
+
return await method(payload.params);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// src/xpc/preload/xpcPreload.emitter.ts
|
|
111
|
+
var createXpcPreloadEmitter = (className) => {
|
|
112
|
+
return new Proxy({}, {
|
|
113
|
+
get(_target, prop) {
|
|
114
|
+
const channel = buildXpcChannel(className, prop);
|
|
115
|
+
return (params) => xpcRenderer.send(channel, params);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
};
|
|
84
119
|
|
|
85
|
-
exports.
|
|
120
|
+
exports.XpcPreloadHandler = XpcPreloadHandler;
|
|
121
|
+
exports.createXpcPreloadEmitter = createXpcPreloadEmitter;
|
|
122
|
+
exports.xpcHandlers = xpcHandlers;
|
|
86
123
|
exports.xpcRenderer = xpcRenderer;
|
|
87
124
|
//# sourceMappingURL=index.js.map
|
|
88
125
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/xpc/preload/xpc-id.helper.ts","../../../src/xpc/preload/xpc-renderer.helper.ts"],"names":["ipcRenderer"],"mappings":";;;;;;;AAKA,IAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AACpD,IAAI,OAAA,GAAU,CAAA;AAEP,IAAM,gBAAgB,MAAc;AACzC,EAAA,OAAO,KAAK,MAAM,CAAA,CAAA,EAAA,CAAK,EAAE,OAAA,EAAS,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAChD,CAAA;;;ACNA,IAAM,YAAA,GAAe,kBAAA;AACrB,IAAM,QAAA,GAAW,cAAA;AACjB,IAAM,UAAA,GAAa,gBAAA;AAUnB,IAAM,cAAN,MAAkB;AAAA,EAAlB,WAAA,GAAA;AACE,IAAA,IAAA,CAAQ,QAAA,uBAAe,GAAA,EAAwB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/C,MAAA,CAAO,YAAoB,OAAA,EAA2B;AACpD,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,UAAA,EAAY,OAAO,CAAA;AAGrC,IAAAA,oBAAA,CAAY,IAAA,CAAK,YAAA,EAAc,EAAE,UAAA,EAAY,CAAA;AAG7C,IAAAA,oBAAA,CAAY,EAAA,CAAG,UAAA,EAAY,OAAO,MAAA,EAAQ,OAAA,KAAwB;AAChE,MAAA,IAAI,GAAA,GAAW,IAAA;AACf,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,UAAU,CAAA;AACjD,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,IAAI;AACF,UAAA,GAAA,GAAM,MAAM,aAAa,OAAO,CAAA;AAAA,QAClC,SAAS,EAAA,EAAI;AACX,UAAA,GAAA,GAAM,IAAA;AAAA,QACR;AAAA,MACF;AAEA,MAAAA,oBAAA,CAAY,KAAK,UAAA,EAAY;AAAA,QAC3B,IAAI,OAAA,CAAQ,EAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB;AAAA,OACa,CAAA;AAAA,IACjB,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,UAAA,EAA0B;AACrC,IAAA,IAAA,CAAK,QAAA,CAAS,OAAO,UAAU,CAAA;AAC/B,IAAAA,oBAAA,CAAY,mBAAmB,UAAU,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAA,CAAK,UAAA,EAAoB,MAAA,EAA4B;AACzD,IAAA,MAAM,OAAA,GAAsB;AAAA,MAC1B,IAAI,aAAA,EAAc;AAAA,MAClB,UAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAA,EAAK;AAAA,KACP;AAEA,IAAA,OAAO,MAAMA,oBAAA,CAAY,MAAA,CAAO,QAAA,EAAU,OAAO,CAAA;AAAA,EACnD;AACF,CAAA;AAEO,IAAM,WAAA,GAAc,IAAI,WAAA;AAYxB,IAAM,oBAAoB,MAAsB;AACrD,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAC,UAAA,EAAoB,OAAA,KAAyD;AACpF,MAAA,WAAA,CAAY,MAAA,CAAO,YAAY,OAAO,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,YAAA,EAAc,CAAC,UAAA,KAA6B;AAC1C,MAAA,WAAA,CAAY,aAAa,UAAU,CAAA;AAAA,IACrC,CAAA;AAAA,IACA,IAAA,EAAM,CAAC,UAAA,EAAoB,MAAA,KAA+B;AACxD,MAAA,OAAO,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,MAAM,CAAA;AAAA,IAC5C;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * High-performance process-unique ID generator for renderer process.\n * Combines a random prefix (per process) with an incrementing counter.\n * Guaranteed unique within a single process lifetime.\n */\nconst prefix = Math.random().toString(36).slice(2, 8);\nlet counter = 0;\n\nexport const generateXpcId = (): string => {\n return `r-${prefix}-${(++counter).toString(36)}`;\n};\n","import { ipcRenderer } from 'electron';\nimport { XpcPayload } from '../shared/xpc.type';\nimport { generateXpcId } from './xpc-id.helper';\n\nconst XPC_REGISTER = '__xpc_register__';\nconst XPC_EXEC = '__xpc_exec__';\nconst XPC_FINISH = '__xpc_finish__';\n\ntype XpcHandler = (payload: XpcPayload) => Promise<any>;\n\n/**\n * XpcRenderer: runs in the renderer process (via preload).\n * - register({handleName}): registers a handleName with main process, also sets up local listener\n * - handle(handleName, handler): registers handler locally + sends __xpc_register__ to main\n * - send(handleName, params): invokes __xpc_exec__ on main, awaits result via ipcRenderer.invoke\n */\nclass XpcRenderer {\n private handlers = new Map<string, XpcHandler>();\n\n /**\n * Register a handleName with the main process and bind a local async handler.\n * When another renderer calls send() with this handleName, xpcCenter will forward\n * the payload to this renderer, the handler executes, and result is sent back via __xpc_finish__.\n */\n handle(handleName: string, handler: XpcHandler): void {\n this.handlers.set(handleName, handler);\n\n // Notify main process about this registration\n ipcRenderer.send(XPC_REGISTER, { handleName });\n\n // Listen for incoming handleName events forwarded by xpcCenter\n ipcRenderer.on(handleName, async (_event, payload: XpcPayload) => {\n let ret: any = null;\n const localHandler = this.handlers.get(handleName);\n if (localHandler) {\n try {\n ret = await localHandler(payload);\n } catch (_e) {\n ret = null;\n }\n }\n // Send __xpc_finish__ back to main with result\n ipcRenderer.send(XPC_FINISH, {\n id: payload.id,\n handleName: payload.handleName,\n params: payload.params,\n ret,\n } as XpcPayload);\n });\n }\n\n /**\n * Remove a registered handler.\n */\n removeHandle(handleName: string): void {\n this.handlers.delete(handleName);\n ipcRenderer.removeAllListeners(handleName);\n }\n\n /**\n * Send a message to another renderer (or any registered handler) via main process.\n * Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.\n * Returns the ret value from the target handler, or null.\n */\n async send(handleName: string, params?: any): Promise<any> {\n const payload: XpcPayload = {\n id: generateXpcId(),\n handleName,\n params,\n ret: null,\n };\n\n return await ipcRenderer.invoke(XPC_EXEC, payload);\n }\n}\n\nexport const xpcRenderer = new XpcRenderer();\n\nexport type XpcRendererApi = {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>) => void;\n removeHandle: (handleName: string) => void;\n send: (handleName: string, params?: any) => Promise<any>;\n};\n\n/**\n * Returns a contextBridge-safe object for exposeInMainWorld.\n * Usage: contextBridge.exposeInMainWorld('xpcRenderer', exposeXpcRenderer())\n */\nexport const exposeXpcRenderer = (): XpcRendererApi => {\n return {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>): void => {\n xpcRenderer.handle(handleName, handler);\n },\n removeHandle: (handleName: string): void => {\n xpcRenderer.removeHandle(handleName);\n },\n send: (handleName: string, params?: any): Promise<any> => {\n return xpcRenderer.send(handleName, params);\n },\n };\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/xpc/preload/xpcId.helper.ts","../../../src/xpc/preload/xpcPreload.helper.ts","../../../src/xpc/shared/xpcHandler.type.ts","../../../src/xpc/preload/xpcPreload.handler.ts","../../../src/xpc/preload/xpcPreload.emitter.ts"],"names":["ipcRenderer","contextBridge"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * High-performance process-unique ID generator for renderer process.\n * Combines a random prefix (per process) with an incrementing counter.\n * Guaranteed unique within a single process lifetime.\n */\nconst prefix = Math.random().toString(36).slice(2, 8);\nlet counter = 0;\n\nexport const generateXpcId = (): string => {\n return `r-${prefix}-${(++counter).toString(36)}`;\n};\n","import { contextBridge, ipcRenderer } from 'electron';\nimport { XpcPayload, XpcRendererApi } from '../shared/xpc.type';\nimport { generateXpcId } from './xpcId.helper';\n\nconst XPC_REGISTER = '__xpc_register__';\nconst XPC_EXEC = '__xpc_exec__';\nconst XPC_FINISH = '__xpc_finish__';\n\ntype XpcHandler = (payload: XpcPayload) => Promise<any>;\n\n/** Global handlers map, extracted from XpcRenderer class */\nexport const xpcHandlers = new Map<string, XpcHandler>();\n\nexport type { XpcRendererApi } from '../shared/xpc.type';\n\n/**\n * Register a handleName with the main process and bind a local async handler.\n * When another renderer calls send() with this handleName, xpcCenter will forward\n * the payload to this renderer, the handler executes, and result is sent back via __xpc_finish__.\n */\nconst handle = (handleName: string, handler: XpcHandler): void => {\n xpcHandlers.set(handleName, handler);\n\n // Notify main process about this registration\n ipcRenderer.send(XPC_REGISTER, { handleName });\n\n // Listen for incoming handleName events forwarded by xpcCenter\n ipcRenderer.on(handleName, async (_event, payload: XpcPayload) => {\n let ret: any = null;\n const localHandler = xpcHandlers.get(handleName);\n if (localHandler) {\n try {\n ret = await localHandler(payload);\n } catch (_e) {\n ret = null;\n }\n }\n // Send __xpc_finish__ back to main with result\n ipcRenderer.send(XPC_FINISH, {\n id: payload.id,\n handleName: payload.handleName,\n params: payload.params,\n ret,\n } as XpcPayload);\n });\n};\n\n/**\n * Remove a registered handler.\n */\nconst removeHandle = (handleName: string): void => {\n xpcHandlers.delete(handleName);\n ipcRenderer.removeAllListeners(handleName);\n};\n\n/**\n * Send a message to another renderer (or any registered handler) via main process.\n * Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.\n * Returns the ret value from the target handler, or null.\n */\nconst send = async (handleName: string, params?: any): Promise<any> => {\n const payload: XpcPayload = {\n id: generateXpcId(),\n handleName,\n params,\n ret: null,\n };\n\n return await ipcRenderer.invoke(XPC_EXEC, payload);\n};\n\n/**\n * Returns a contextBridge-safe object for exposeInMainWorld.\n */\nconst createXpcRendererApi = (): XpcRendererApi => {\n return {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>): void => {\n handle(handleName, handler);\n },\n removeHandle: (handleName: string): void => {\n removeHandle(handleName);\n },\n send: (handleName: string, params?: any): Promise<any> => {\n return send(handleName, params);\n },\n };\n};\n\n/** The xpcRenderer API instance */\nexport const xpcRenderer: XpcRendererApi = createXpcRendererApi();\n\n// Auto-expose xpcRenderer to window on import\nif (process.contextIsolated) {\n try {\n contextBridge.exposeInMainWorld('xpcRenderer', xpcRenderer);\n } catch (error) {\n console.error('[xpcPreload] exposeInMainWorld failed:', error);\n }\n} else {\n (globalThis as any).xpcRenderer = xpcRenderer;\n}\n","/**\n * Prefix for all auto-registered xpc handler channels.\n * Channel format: `xpc:ClassName/methodName`\n */\nexport const XPC_HANDLER_PREFIX = 'xpc:';\n\n/**\n * Build the xpc channel name from class name and method name.\n * e.g. buildChannel('UserTable', 'getUserList') => 'xpc:UserTable/getUserList'\n */\nexport const buildXpcChannel = (className: string, methodName: string): string => {\n return `${XPC_HANDLER_PREFIX}${className}/${methodName}`;\n};\n\n/**\n * Extract own method names from a class prototype, excluding constructor.\n */\nexport const getHandlerMethodNames = (prototype: object): string[] => {\n const names: string[] = [];\n const keys = Object.getOwnPropertyNames(prototype);\n for (const key of keys) {\n if (key === 'constructor') continue;\n const descriptor = Object.getOwnPropertyDescriptor(prototype, key);\n if (descriptor && typeof descriptor.value === 'function') {\n names.push(key);\n }\n }\n return names;\n};\n\n/**\n * Constraint: handler methods must accept 0 or 1 parameter.\n * Methods with 2+ parameters will fail type checking.\n */\nexport type XpcHandlerMethod = (() => Promise<any>) | ((params: any) => Promise<any>);\n\n/**\n * Helper: checks if a function type has at most 1 parameter.\n * Returns the function type itself if valid, `never` otherwise.\n */\ntype AssertSingleParam<F> =\n F extends () => any ? F :\n F extends (p: any) => any ?\n F extends (p: any, q: any, ...rest: any[]) => any ? never : F\n : never;\n\n/**\n * Utility type: extracts the method signatures from a handler class,\n * turning each method into an emitter-compatible signature.\n * Methods with 2+ parameters are mapped to `never`, causing a compile error on use.\n */\nexport type XpcEmitterOf<T> = {\n [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]:\n AssertSingleParam<T[K]> extends never\n ? never\n : T[K] extends (params: infer P) => any\n ? (params: P) => Promise<any>\n : () => Promise<any>;\n};\n","import { XpcPayload } from '../shared/xpc.type';\nimport { buildXpcChannel, getHandlerMethodNames } from '../shared/xpcHandler.type';\nimport { xpcRenderer } from './xpcPreload.helper';\n\n/**\n * Base class for preload-process xpc handlers.\n * Subclass this and define async methods — they will be auto-registered\n * as xpc handlers with channel `xpc:ClassName/methodName`.\n *\n * Example:\n * ```ts\n * class UserTable extends XpcPreloadHandler {\n * async getUserList(params?: any): Promise<any> { ... }\n * }\n * const userTable = new UserTable();\n * // auto-registers handler for 'xpc:UserTable/getUserList'\n * ```\n */\nexport class XpcPreloadHandler {\n constructor() {\n const className = this.constructor.name;\n const methodNames = getHandlerMethodNames(Object.getPrototypeOf(this));\n for (const methodName of methodNames) {\n const channel = buildXpcChannel(className, methodName);\n const method = (this as any)[methodName].bind(this);\n xpcRenderer.handle(channel, async (payload: XpcPayload) => {\n return await method(payload.params);\n });\n }\n }\n}\n","import { buildXpcChannel, XpcEmitterOf } from '../shared/xpcHandler.type';\nimport { xpcRenderer } from './xpcPreload.helper';\n\n/**\n * Create a type-safe emitter proxy for a preload-process xpc handler.\n * The emitter mirrors the handler's method signatures, but each call\n * sends a message via xpcRenderer.send() to `xpc:ClassName/methodName`.\n *\n * Example:\n * ```ts\n * class UserTable extends XpcPreloadHandler {\n * async getUserList(params?: any): Promise<any> { ... }\n * }\n * const userTableEmitter = createXpcPreloadEmitter<UserTable>('UserTable');\n * const list = await userTableEmitter.getUserList({ page: 1 });\n * // sends to 'xpc:UserTable/getUserList'\n * ```\n */\nexport const createXpcPreloadEmitter = <T>(className: string): XpcEmitterOf<T> => {\n return new Proxy({} as XpcEmitterOf<T>, {\n get(_target, prop: string) {\n const channel = buildXpcChannel(className, prop);\n return (params?: any) => xpcRenderer.send(channel, params);\n },\n });\n};\n"]}
|
|
@@ -1,85 +1,120 @@
|
|
|
1
|
-
import { ipcRenderer } from 'electron';
|
|
1
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
2
2
|
|
|
3
|
-
// src/xpc/preload/
|
|
3
|
+
// src/xpc/preload/xpcPreload.helper.ts
|
|
4
4
|
|
|
5
|
-
// src/xpc/preload/
|
|
5
|
+
// src/xpc/preload/xpcId.helper.ts
|
|
6
6
|
var prefix = Math.random().toString(36).slice(2, 8);
|
|
7
7
|
var counter = 0;
|
|
8
8
|
var generateXpcId = () => {
|
|
9
9
|
return `r-${prefix}-${(++counter).toString(36)}`;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// src/xpc/preload/
|
|
12
|
+
// src/xpc/preload/xpcPreload.helper.ts
|
|
13
13
|
var XPC_REGISTER = "__xpc_register__";
|
|
14
14
|
var XPC_EXEC = "__xpc_exec__";
|
|
15
15
|
var XPC_FINISH = "__xpc_finish__";
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
ipcRenderer.on(handleName, async (_event, payload) => {
|
|
29
|
-
let ret = null;
|
|
30
|
-
const localHandler = this.handlers.get(handleName);
|
|
31
|
-
if (localHandler) {
|
|
32
|
-
try {
|
|
33
|
-
ret = await localHandler(payload);
|
|
34
|
-
} catch (_e) {
|
|
35
|
-
ret = null;
|
|
36
|
-
}
|
|
16
|
+
var xpcHandlers = /* @__PURE__ */ new Map();
|
|
17
|
+
var handle = (handleName, handler) => {
|
|
18
|
+
xpcHandlers.set(handleName, handler);
|
|
19
|
+
ipcRenderer.send(XPC_REGISTER, { handleName });
|
|
20
|
+
ipcRenderer.on(handleName, async (_event, payload) => {
|
|
21
|
+
let ret = null;
|
|
22
|
+
const localHandler = xpcHandlers.get(handleName);
|
|
23
|
+
if (localHandler) {
|
|
24
|
+
try {
|
|
25
|
+
ret = await localHandler(payload);
|
|
26
|
+
} catch (_e) {
|
|
27
|
+
ret = null;
|
|
37
28
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
}
|
|
30
|
+
ipcRenderer.send(XPC_FINISH, {
|
|
31
|
+
id: payload.id,
|
|
32
|
+
handleName: payload.handleName,
|
|
33
|
+
params: payload.params,
|
|
34
|
+
ret
|
|
44
35
|
});
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Remove a registered handler.
|
|
48
|
-
*/
|
|
49
|
-
removeHandle(handleName) {
|
|
50
|
-
this.handlers.delete(handleName);
|
|
51
|
-
ipcRenderer.removeAllListeners(handleName);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Send a message to another renderer (or any registered handler) via main process.
|
|
55
|
-
* Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.
|
|
56
|
-
* Returns the ret value from the target handler, or null.
|
|
57
|
-
*/
|
|
58
|
-
async send(handleName, params) {
|
|
59
|
-
const payload = {
|
|
60
|
-
id: generateXpcId(),
|
|
61
|
-
handleName,
|
|
62
|
-
params,
|
|
63
|
-
ret: null
|
|
64
|
-
};
|
|
65
|
-
return await ipcRenderer.invoke(XPC_EXEC, payload);
|
|
66
|
-
}
|
|
36
|
+
});
|
|
67
37
|
};
|
|
68
|
-
var
|
|
69
|
-
|
|
38
|
+
var removeHandle = (handleName) => {
|
|
39
|
+
xpcHandlers.delete(handleName);
|
|
40
|
+
ipcRenderer.removeAllListeners(handleName);
|
|
41
|
+
};
|
|
42
|
+
var send = async (handleName, params) => {
|
|
43
|
+
const payload = {
|
|
44
|
+
id: generateXpcId(),
|
|
45
|
+
handleName,
|
|
46
|
+
params,
|
|
47
|
+
ret: null
|
|
48
|
+
};
|
|
49
|
+
return await ipcRenderer.invoke(XPC_EXEC, payload);
|
|
50
|
+
};
|
|
51
|
+
var createXpcRendererApi = () => {
|
|
70
52
|
return {
|
|
71
53
|
handle: (handleName, handler) => {
|
|
72
|
-
|
|
54
|
+
handle(handleName, handler);
|
|
73
55
|
},
|
|
74
56
|
removeHandle: (handleName) => {
|
|
75
|
-
|
|
57
|
+
removeHandle(handleName);
|
|
76
58
|
},
|
|
77
59
|
send: (handleName, params) => {
|
|
78
|
-
return
|
|
60
|
+
return send(handleName, params);
|
|
79
61
|
}
|
|
80
62
|
};
|
|
81
63
|
};
|
|
64
|
+
var xpcRenderer = createXpcRendererApi();
|
|
65
|
+
if (process.contextIsolated) {
|
|
66
|
+
try {
|
|
67
|
+
contextBridge.exposeInMainWorld("xpcRenderer", xpcRenderer);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("[xpcPreload] exposeInMainWorld failed:", error);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
globalThis.xpcRenderer = xpcRenderer;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/xpc/shared/xpcHandler.type.ts
|
|
76
|
+
var XPC_HANDLER_PREFIX = "xpc:";
|
|
77
|
+
var buildXpcChannel = (className, methodName) => {
|
|
78
|
+
return `${XPC_HANDLER_PREFIX}${className}/${methodName}`;
|
|
79
|
+
};
|
|
80
|
+
var getHandlerMethodNames = (prototype) => {
|
|
81
|
+
const names = [];
|
|
82
|
+
const keys = Object.getOwnPropertyNames(prototype);
|
|
83
|
+
for (const key of keys) {
|
|
84
|
+
if (key === "constructor") continue;
|
|
85
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
86
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
87
|
+
names.push(key);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return names;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/xpc/preload/xpcPreload.handler.ts
|
|
94
|
+
var XpcPreloadHandler = class {
|
|
95
|
+
constructor() {
|
|
96
|
+
const className = this.constructor.name;
|
|
97
|
+
const methodNames = getHandlerMethodNames(Object.getPrototypeOf(this));
|
|
98
|
+
for (const methodName of methodNames) {
|
|
99
|
+
const channel = buildXpcChannel(className, methodName);
|
|
100
|
+
const method = this[methodName].bind(this);
|
|
101
|
+
xpcRenderer.handle(channel, async (payload) => {
|
|
102
|
+
return await method(payload.params);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// src/xpc/preload/xpcPreload.emitter.ts
|
|
109
|
+
var createXpcPreloadEmitter = (className) => {
|
|
110
|
+
return new Proxy({}, {
|
|
111
|
+
get(_target, prop) {
|
|
112
|
+
const channel = buildXpcChannel(className, prop);
|
|
113
|
+
return (params) => xpcRenderer.send(channel, params);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
82
117
|
|
|
83
|
-
export {
|
|
118
|
+
export { XpcPreloadHandler, createXpcPreloadEmitter, xpcHandlers, xpcRenderer };
|
|
84
119
|
//# sourceMappingURL=index.mjs.map
|
|
85
120
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/xpc/preload/xpc-id.helper.ts","../../../src/xpc/preload/xpc-renderer.helper.ts"],"names":[],"mappings":";;;;;AAKA,IAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AACpD,IAAI,OAAA,GAAU,CAAA;AAEP,IAAM,gBAAgB,MAAc;AACzC,EAAA,OAAO,KAAK,MAAM,CAAA,CAAA,EAAA,CAAK,EAAE,OAAA,EAAS,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAChD,CAAA;;;ACNA,IAAM,YAAA,GAAe,kBAAA;AACrB,IAAM,QAAA,GAAW,cAAA;AACjB,IAAM,UAAA,GAAa,gBAAA;AAUnB,IAAM,cAAN,MAAkB;AAAA,EAAlB,WAAA,GAAA;AACE,IAAA,IAAA,CAAQ,QAAA,uBAAe,GAAA,EAAwB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/C,MAAA,CAAO,YAAoB,OAAA,EAA2B;AACpD,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,UAAA,EAAY,OAAO,CAAA;AAGrC,IAAA,WAAA,CAAY,IAAA,CAAK,YAAA,EAAc,EAAE,UAAA,EAAY,CAAA;AAG7C,IAAA,WAAA,CAAY,EAAA,CAAG,UAAA,EAAY,OAAO,MAAA,EAAQ,OAAA,KAAwB;AAChE,MAAA,IAAI,GAAA,GAAW,IAAA;AACf,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,UAAU,CAAA;AACjD,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,IAAI;AACF,UAAA,GAAA,GAAM,MAAM,aAAa,OAAO,CAAA;AAAA,QAClC,SAAS,EAAA,EAAI;AACX,UAAA,GAAA,GAAM,IAAA;AAAA,QACR;AAAA,MACF;AAEA,MAAA,WAAA,CAAY,KAAK,UAAA,EAAY;AAAA,QAC3B,IAAI,OAAA,CAAQ,EAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB;AAAA,OACa,CAAA;AAAA,IACjB,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,UAAA,EAA0B;AACrC,IAAA,IAAA,CAAK,QAAA,CAAS,OAAO,UAAU,CAAA;AAC/B,IAAA,WAAA,CAAY,mBAAmB,UAAU,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAA,CAAK,UAAA,EAAoB,MAAA,EAA4B;AACzD,IAAA,MAAM,OAAA,GAAsB;AAAA,MAC1B,IAAI,aAAA,EAAc;AAAA,MAClB,UAAA;AAAA,MACA,MAAA;AAAA,MACA,GAAA,EAAK;AAAA,KACP;AAEA,IAAA,OAAO,MAAM,WAAA,CAAY,MAAA,CAAO,QAAA,EAAU,OAAO,CAAA;AAAA,EACnD;AACF,CAAA;AAEO,IAAM,WAAA,GAAc,IAAI,WAAA;AAYxB,IAAM,oBAAoB,MAAsB;AACrD,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAC,UAAA,EAAoB,OAAA,KAAyD;AACpF,MAAA,WAAA,CAAY,MAAA,CAAO,YAAY,OAAO,CAAA;AAAA,IACxC,CAAA;AAAA,IACA,YAAA,EAAc,CAAC,UAAA,KAA6B;AAC1C,MAAA,WAAA,CAAY,aAAa,UAAU,CAAA;AAAA,IACrC,CAAA;AAAA,IACA,IAAA,EAAM,CAAC,UAAA,EAAoB,MAAA,KAA+B;AACxD,MAAA,OAAO,WAAA,CAAY,IAAA,CAAK,UAAA,EAAY,MAAM,CAAA;AAAA,IAC5C;AAAA,GACF;AACF","file":"index.mjs","sourcesContent":["/**\n * High-performance process-unique ID generator for renderer process.\n * Combines a random prefix (per process) with an incrementing counter.\n * Guaranteed unique within a single process lifetime.\n */\nconst prefix = Math.random().toString(36).slice(2, 8);\nlet counter = 0;\n\nexport const generateXpcId = (): string => {\n return `r-${prefix}-${(++counter).toString(36)}`;\n};\n","import { ipcRenderer } from 'electron';\nimport { XpcPayload } from '../shared/xpc.type';\nimport { generateXpcId } from './xpc-id.helper';\n\nconst XPC_REGISTER = '__xpc_register__';\nconst XPC_EXEC = '__xpc_exec__';\nconst XPC_FINISH = '__xpc_finish__';\n\ntype XpcHandler = (payload: XpcPayload) => Promise<any>;\n\n/**\n * XpcRenderer: runs in the renderer process (via preload).\n * - register({handleName}): registers a handleName with main process, also sets up local listener\n * - handle(handleName, handler): registers handler locally + sends __xpc_register__ to main\n * - send(handleName, params): invokes __xpc_exec__ on main, awaits result via ipcRenderer.invoke\n */\nclass XpcRenderer {\n private handlers = new Map<string, XpcHandler>();\n\n /**\n * Register a handleName with the main process and bind a local async handler.\n * When another renderer calls send() with this handleName, xpcCenter will forward\n * the payload to this renderer, the handler executes, and result is sent back via __xpc_finish__.\n */\n handle(handleName: string, handler: XpcHandler): void {\n this.handlers.set(handleName, handler);\n\n // Notify main process about this registration\n ipcRenderer.send(XPC_REGISTER, { handleName });\n\n // Listen for incoming handleName events forwarded by xpcCenter\n ipcRenderer.on(handleName, async (_event, payload: XpcPayload) => {\n let ret: any = null;\n const localHandler = this.handlers.get(handleName);\n if (localHandler) {\n try {\n ret = await localHandler(payload);\n } catch (_e) {\n ret = null;\n }\n }\n // Send __xpc_finish__ back to main with result\n ipcRenderer.send(XPC_FINISH, {\n id: payload.id,\n handleName: payload.handleName,\n params: payload.params,\n ret,\n } as XpcPayload);\n });\n }\n\n /**\n * Remove a registered handler.\n */\n removeHandle(handleName: string): void {\n this.handlers.delete(handleName);\n ipcRenderer.removeAllListeners(handleName);\n }\n\n /**\n * Send a message to another renderer (or any registered handler) via main process.\n * Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.\n * Returns the ret value from the target handler, or null.\n */\n async send(handleName: string, params?: any): Promise<any> {\n const payload: XpcPayload = {\n id: generateXpcId(),\n handleName,\n params,\n ret: null,\n };\n\n return await ipcRenderer.invoke(XPC_EXEC, payload);\n }\n}\n\nexport const xpcRenderer = new XpcRenderer();\n\nexport type XpcRendererApi = {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>) => void;\n removeHandle: (handleName: string) => void;\n send: (handleName: string, params?: any) => Promise<any>;\n};\n\n/**\n * Returns a contextBridge-safe object for exposeInMainWorld.\n * Usage: contextBridge.exposeInMainWorld('xpcRenderer', exposeXpcRenderer())\n */\nexport const exposeXpcRenderer = (): XpcRendererApi => {\n return {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>): void => {\n xpcRenderer.handle(handleName, handler);\n },\n removeHandle: (handleName: string): void => {\n xpcRenderer.removeHandle(handleName);\n },\n send: (handleName: string, params?: any): Promise<any> => {\n return xpcRenderer.send(handleName, params);\n },\n };\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/xpc/preload/xpcId.helper.ts","../../../src/xpc/preload/xpcPreload.helper.ts","../../../src/xpc/shared/xpcHandler.type.ts","../../../src/xpc/preload/xpcPreload.handler.ts","../../../src/xpc/preload/xpcPreload.emitter.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * High-performance process-unique ID generator for renderer process.\n * Combines a random prefix (per process) with an incrementing counter.\n * Guaranteed unique within a single process lifetime.\n */\nconst prefix = Math.random().toString(36).slice(2, 8);\nlet counter = 0;\n\nexport const generateXpcId = (): string => {\n return `r-${prefix}-${(++counter).toString(36)}`;\n};\n","import { contextBridge, ipcRenderer } from 'electron';\nimport { XpcPayload, XpcRendererApi } from '../shared/xpc.type';\nimport { generateXpcId } from './xpcId.helper';\n\nconst XPC_REGISTER = '__xpc_register__';\nconst XPC_EXEC = '__xpc_exec__';\nconst XPC_FINISH = '__xpc_finish__';\n\ntype XpcHandler = (payload: XpcPayload) => Promise<any>;\n\n/** Global handlers map, extracted from XpcRenderer class */\nexport const xpcHandlers = new Map<string, XpcHandler>();\n\nexport type { XpcRendererApi } from '../shared/xpc.type';\n\n/**\n * Register a handleName with the main process and bind a local async handler.\n * When another renderer calls send() with this handleName, xpcCenter will forward\n * the payload to this renderer, the handler executes, and result is sent back via __xpc_finish__.\n */\nconst handle = (handleName: string, handler: XpcHandler): void => {\n xpcHandlers.set(handleName, handler);\n\n // Notify main process about this registration\n ipcRenderer.send(XPC_REGISTER, { handleName });\n\n // Listen for incoming handleName events forwarded by xpcCenter\n ipcRenderer.on(handleName, async (_event, payload: XpcPayload) => {\n let ret: any = null;\n const localHandler = xpcHandlers.get(handleName);\n if (localHandler) {\n try {\n ret = await localHandler(payload);\n } catch (_e) {\n ret = null;\n }\n }\n // Send __xpc_finish__ back to main with result\n ipcRenderer.send(XPC_FINISH, {\n id: payload.id,\n handleName: payload.handleName,\n params: payload.params,\n ret,\n } as XpcPayload);\n });\n};\n\n/**\n * Remove a registered handler.\n */\nconst removeHandle = (handleName: string): void => {\n xpcHandlers.delete(handleName);\n ipcRenderer.removeAllListeners(handleName);\n};\n\n/**\n * Send a message to another renderer (or any registered handler) via main process.\n * Uses ipcRenderer.invoke(__xpc_exec__) which blocks until the target finishes.\n * Returns the ret value from the target handler, or null.\n */\nconst send = async (handleName: string, params?: any): Promise<any> => {\n const payload: XpcPayload = {\n id: generateXpcId(),\n handleName,\n params,\n ret: null,\n };\n\n return await ipcRenderer.invoke(XPC_EXEC, payload);\n};\n\n/**\n * Returns a contextBridge-safe object for exposeInMainWorld.\n */\nconst createXpcRendererApi = (): XpcRendererApi => {\n return {\n handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>): void => {\n handle(handleName, handler);\n },\n removeHandle: (handleName: string): void => {\n removeHandle(handleName);\n },\n send: (handleName: string, params?: any): Promise<any> => {\n return send(handleName, params);\n },\n };\n};\n\n/** The xpcRenderer API instance */\nexport const xpcRenderer: XpcRendererApi = createXpcRendererApi();\n\n// Auto-expose xpcRenderer to window on import\nif (process.contextIsolated) {\n try {\n contextBridge.exposeInMainWorld('xpcRenderer', xpcRenderer);\n } catch (error) {\n console.error('[xpcPreload] exposeInMainWorld failed:', error);\n }\n} else {\n (globalThis as any).xpcRenderer = xpcRenderer;\n}\n","/**\n * Prefix for all auto-registered xpc handler channels.\n * Channel format: `xpc:ClassName/methodName`\n */\nexport const XPC_HANDLER_PREFIX = 'xpc:';\n\n/**\n * Build the xpc channel name from class name and method name.\n * e.g. buildChannel('UserTable', 'getUserList') => 'xpc:UserTable/getUserList'\n */\nexport const buildXpcChannel = (className: string, methodName: string): string => {\n return `${XPC_HANDLER_PREFIX}${className}/${methodName}`;\n};\n\n/**\n * Extract own method names from a class prototype, excluding constructor.\n */\nexport const getHandlerMethodNames = (prototype: object): string[] => {\n const names: string[] = [];\n const keys = Object.getOwnPropertyNames(prototype);\n for (const key of keys) {\n if (key === 'constructor') continue;\n const descriptor = Object.getOwnPropertyDescriptor(prototype, key);\n if (descriptor && typeof descriptor.value === 'function') {\n names.push(key);\n }\n }\n return names;\n};\n\n/**\n * Constraint: handler methods must accept 0 or 1 parameter.\n * Methods with 2+ parameters will fail type checking.\n */\nexport type XpcHandlerMethod = (() => Promise<any>) | ((params: any) => Promise<any>);\n\n/**\n * Helper: checks if a function type has at most 1 parameter.\n * Returns the function type itself if valid, `never` otherwise.\n */\ntype AssertSingleParam<F> =\n F extends () => any ? F :\n F extends (p: any) => any ?\n F extends (p: any, q: any, ...rest: any[]) => any ? never : F\n : never;\n\n/**\n * Utility type: extracts the method signatures from a handler class,\n * turning each method into an emitter-compatible signature.\n * Methods with 2+ parameters are mapped to `never`, causing a compile error on use.\n */\nexport type XpcEmitterOf<T> = {\n [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]:\n AssertSingleParam<T[K]> extends never\n ? never\n : T[K] extends (params: infer P) => any\n ? (params: P) => Promise<any>\n : () => Promise<any>;\n};\n","import { XpcPayload } from '../shared/xpc.type';\nimport { buildXpcChannel, getHandlerMethodNames } from '../shared/xpcHandler.type';\nimport { xpcRenderer } from './xpcPreload.helper';\n\n/**\n * Base class for preload-process xpc handlers.\n * Subclass this and define async methods — they will be auto-registered\n * as xpc handlers with channel `xpc:ClassName/methodName`.\n *\n * Example:\n * ```ts\n * class UserTable extends XpcPreloadHandler {\n * async getUserList(params?: any): Promise<any> { ... }\n * }\n * const userTable = new UserTable();\n * // auto-registers handler for 'xpc:UserTable/getUserList'\n * ```\n */\nexport class XpcPreloadHandler {\n constructor() {\n const className = this.constructor.name;\n const methodNames = getHandlerMethodNames(Object.getPrototypeOf(this));\n for (const methodName of methodNames) {\n const channel = buildXpcChannel(className, methodName);\n const method = (this as any)[methodName].bind(this);\n xpcRenderer.handle(channel, async (payload: XpcPayload) => {\n return await method(payload.params);\n });\n }\n }\n}\n","import { buildXpcChannel, XpcEmitterOf } from '../shared/xpcHandler.type';\nimport { xpcRenderer } from './xpcPreload.helper';\n\n/**\n * Create a type-safe emitter proxy for a preload-process xpc handler.\n * The emitter mirrors the handler's method signatures, but each call\n * sends a message via xpcRenderer.send() to `xpc:ClassName/methodName`.\n *\n * Example:\n * ```ts\n * class UserTable extends XpcPreloadHandler {\n * async getUserList(params?: any): Promise<any> { ... }\n * }\n * const userTableEmitter = createXpcPreloadEmitter<UserTable>('UserTable');\n * const list = await userTableEmitter.getUserList({ page: 1 });\n * // sends to 'xpc:UserTable/getUserList'\n * ```\n */\nexport const createXpcPreloadEmitter = <T>(className: string): XpcEmitterOf<T> => {\n return new Proxy({} as XpcEmitterOf<T>, {\n get(_target, prop: string) {\n const channel = buildXpcChannel(className, prop);\n return (params?: any) => xpcRenderer.send(channel, params);\n },\n });\n};\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type XpcPayload = {
|
|
2
|
+
/** Unique task ID, guaranteed unique within process lifetime */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Event handle name */
|
|
5
|
+
handleName: string;
|
|
6
|
+
/** Parameters, nullable */
|
|
7
|
+
params?: any;
|
|
8
|
+
/** Return data from target process, nullable, defaults to null */
|
|
9
|
+
ret?: any;
|
|
10
|
+
};
|
|
11
|
+
type XpcRendererApi = {
|
|
12
|
+
handle: (handleName: string, handler: (payload: XpcPayload) => Promise<any>) => void;
|
|
13
|
+
removeHandle: (handleName: string) => void;
|
|
14
|
+
send: (handleName: string, params?: any) => Promise<any>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Direct reference to window.xpcRenderer exposed by the preload script.
|
|
19
|
+
* Import this in renderer (browser) code to use xpcRenderer without manual window casting.
|
|
20
|
+
*/
|
|
21
|
+
declare const xpcRenderer: XpcRendererApi;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Base class for renderer-process xpc handlers.
|
|
25
|
+
* Subclass this and define async methods — they will be auto-registered
|
|
26
|
+
* as xpc handlers with channel `xpc:ClassName/methodName`.
|
|
27
|
+
*
|
|
28
|
+
* Example:
|
|
29
|
+
* ```ts
|
|
30
|
+
* class UserTable extends XpcRendererHandler {
|
|
31
|
+
* async getUserList(params?: any): Promise<any> { ... }
|
|
32
|
+
* }
|
|
33
|
+
* const userTable = new UserTable();
|
|
34
|
+
* // auto-registers handler for 'xpc:UserTable/getUserList'
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
declare class XpcRendererHandler {
|
|
38
|
+
constructor();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Helper: checks if a function type has at most 1 parameter.
|
|
43
|
+
* Returns the function type itself if valid, `never` otherwise.
|
|
44
|
+
*/
|
|
45
|
+
type AssertSingleParam<F> = F extends () => any ? F : F extends (p: any) => any ? F extends (p: any, q: any, ...rest: any[]) => any ? never : F : never;
|
|
46
|
+
/**
|
|
47
|
+
* Utility type: extracts the method signatures from a handler class,
|
|
48
|
+
* turning each method into an emitter-compatible signature.
|
|
49
|
+
* Methods with 2+ parameters are mapped to `never`, causing a compile error on use.
|
|
50
|
+
*/
|
|
51
|
+
type XpcEmitterOf<T> = {
|
|
52
|
+
[K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: AssertSingleParam<T[K]> extends never ? never : T[K] extends (params: infer P) => any ? (params: P) => Promise<any> : () => Promise<any>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a type-safe emitter proxy for a renderer-process xpc handler.
|
|
57
|
+
* The emitter mirrors the handler's method signatures, but each call
|
|
58
|
+
* sends a message via xpcRenderer.send() to `xpc:ClassName/methodName`.
|
|
59
|
+
*
|
|
60
|
+
* Example:
|
|
61
|
+
* ```ts
|
|
62
|
+
* class UserTable extends XpcRendererHandler {
|
|
63
|
+
* async getUserList(params?: any): Promise<any> { ... }
|
|
64
|
+
* }
|
|
65
|
+
* const userTableEmitter = createXpcRendererEmitter<UserTable>('UserTable');
|
|
66
|
+
* const list = await userTableEmitter.getUserList({ page: 1 });
|
|
67
|
+
* // sends to 'xpc:UserTable/getUserList'
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare const createXpcRendererEmitter: <T>(className: string) => XpcEmitterOf<T>;
|
|
71
|
+
|
|
72
|
+
export { type XpcEmitterOf, type XpcPayload, type XpcRendererApi, XpcRendererHandler, createXpcRendererEmitter, xpcRenderer };
|