@chenpeiyuan/electron-message 1.0.1

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/dist/index.cjs ADDED
@@ -0,0 +1,294 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // main/index.ts
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ Main: () => Main,
33
+ Preload: () => Preload
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // main/Preload.ts
38
+ var import_electron = require("electron");
39
+
40
+ // main/Base.ts
41
+ var toErrorObject = (obj) => {
42
+ if (obj instanceof Error) {
43
+ const result = {
44
+ error: obj.name,
45
+ stack: obj.stack,
46
+ cause: obj.cause,
47
+ message: obj.message
48
+ };
49
+ if ("extras" in obj) {
50
+ result.extras = obj["extras"];
51
+ }
52
+ return result;
53
+ }
54
+ return obj;
55
+ };
56
+ var log = function(...args) {
57
+ console.log(...args);
58
+ };
59
+ var reqChannel = "runService:req";
60
+ var resChannel = "runService:res";
61
+ var defaultConfig = {
62
+ reqChannel,
63
+ resChannel,
64
+ toErrorObject,
65
+ log: {
66
+ trace: log,
67
+ debug: log,
68
+ info: log,
69
+ warn: log,
70
+ error: log
71
+ }
72
+ };
73
+ var Base = class {
74
+ inited = false;
75
+ services = /* @__PURE__ */ new Map();
76
+ config;
77
+ constructor(config) {
78
+ this.config = Object.assign({}, defaultConfig, config);
79
+ }
80
+ /**
81
+ * 获取服务
82
+ * @param key
83
+ * @returns
84
+ */
85
+ getService(key) {
86
+ return this.services.get(key);
87
+ }
88
+ /**
89
+ * 添加服务
90
+ * @param key
91
+ * @param service
92
+ */
93
+ addService(key, service) {
94
+ this.services.set(key, service);
95
+ }
96
+ /**
97
+ * 添加多个服务
98
+ * @param services
99
+ */
100
+ addServices(services) {
101
+ Object.entries(services).forEach(([key, service]) => {
102
+ this.addService(key, service);
103
+ });
104
+ }
105
+ /**
106
+ * 删除服务
107
+ * @param key
108
+ */
109
+ delService(key) {
110
+ this.services.delete(key);
111
+ }
112
+ /**
113
+ * 初始化
114
+ * @returns
115
+ */
116
+ init() {
117
+ if (this.inited) {
118
+ return;
119
+ }
120
+ this.inited = true;
121
+ this.doInit();
122
+ }
123
+ doInit() {
124
+ return;
125
+ }
126
+ };
127
+
128
+ // main/reqEvent.ts
129
+ var import_zod = __toESM(require("zod"), 1);
130
+ var ServiceReqEventSchema = import_zod.default.object({
131
+ id: import_zod.default.string(),
132
+ api: import_zod.default.string(),
133
+ dst: import_zod.default.string(),
134
+ src: import_zod.default.string(),
135
+ params: import_zod.default.array(import_zod.default.any()),
136
+ reqAt: import_zod.default.number()
137
+ });
138
+ function generateId() {
139
+ const prefix = Date.now().toString(36);
140
+ const suffix = Math.random().toString(36).substring(2, 6);
141
+ return `${prefix}:${suffix}`;
142
+ }
143
+ function createReqEvent(event) {
144
+ const id = generateId();
145
+ return {
146
+ ...event,
147
+ id,
148
+ reqAt: Date.now()
149
+ };
150
+ }
151
+ function checkReqEvent(event) {
152
+ ServiceReqEventSchema.parse(event);
153
+ }
154
+
155
+ // main/resEvent.ts
156
+ var import_zod2 = __toESM(require("zod"), 1);
157
+ var ServiceResEventSchema = import_zod2.default.object({
158
+ id: import_zod2.default.string(),
159
+ api: import_zod2.default.string(),
160
+ dst: import_zod2.default.string(),
161
+ src: import_zod2.default.string(),
162
+ error: import_zod2.default.object({
163
+ error: import_zod2.default.string(),
164
+ message: import_zod2.default.string(),
165
+ stack: import_zod2.default.string().optional(),
166
+ extras: import_zod2.default.any().optional()
167
+ }).optional(),
168
+ result: import_zod2.default.any().optional(),
169
+ reqAt: import_zod2.default.number(),
170
+ resAt: import_zod2.default.number()
171
+ });
172
+ function createResEvent(reqEvent, resEvent) {
173
+ const {
174
+ id,
175
+ api,
176
+ dst: src,
177
+ src: dst,
178
+ reqAt
179
+ } = reqEvent;
180
+ return {
181
+ ...resEvent,
182
+ id,
183
+ api,
184
+ dst,
185
+ src,
186
+ reqAt,
187
+ resAt: Date.now()
188
+ };
189
+ }
190
+ function checkResEvent(event) {
191
+ ServiceResEventSchema.parse(event);
192
+ }
193
+
194
+ // main/Preload.ts
195
+ var Preload = class extends Base {
196
+ async invoke(reqEvent) {
197
+ const {
198
+ log: log2,
199
+ reqChannel: reqChannel2,
200
+ resChannel: resChannel2
201
+ } = this.config;
202
+ reqEvent = createReqEvent(reqEvent);
203
+ log2.debug(reqChannel2, reqEvent);
204
+ const resEvent = await import_electron.ipcRenderer.invoke(reqChannel2, reqEvent);
205
+ log2.debug(resChannel2, resEvent, { endAt: Date.now() });
206
+ return resEvent.error || resEvent.result;
207
+ }
208
+ doInit() {
209
+ const {
210
+ log: log2,
211
+ reqChannel: reqChannel2,
212
+ resChannel: resChannel2,
213
+ toErrorObject: toErrorObject2
214
+ } = this.config;
215
+ import_electron.ipcRenderer.addListener(reqChannel2, async (event, reqEvent) => {
216
+ log2.debug(reqChannel2, reqEvent);
217
+ checkReqEvent(reqEvent);
218
+ const resEvent = createResEvent(reqEvent, {});
219
+ try {
220
+ const service = this.getService(reqEvent.api);
221
+ if (service == null) {
222
+ throw new Error(`\u5BA2\u6237\u7AEF\u670D\u52A1\u65E0\u6CD5\u627E\u5230: ${reqEvent.api}`);
223
+ }
224
+ resEvent.result = await service(...reqEvent.params);
225
+ } catch (error) {
226
+ resEvent.error = toErrorObject2(error);
227
+ }
228
+ import_electron.ipcRenderer.send(resChannel2, resEvent);
229
+ log2.debug(resChannel2, resEvent);
230
+ });
231
+ }
232
+ };
233
+
234
+ // main/Main.ts
235
+ var import_electron2 = require("electron");
236
+ var Main = class extends Base {
237
+ resolvers = /* @__PURE__ */ new Map();
238
+ doInit() {
239
+ const {
240
+ log: log2,
241
+ reqChannel: reqChannel2,
242
+ resChannel: resChannel2,
243
+ toErrorObject: toErrorObject2
244
+ } = this.config;
245
+ import_electron2.ipcMain.handle(reqChannel2, async (event, reqEvent) => {
246
+ log2.debug(reqChannel2, reqEvent);
247
+ checkReqEvent(reqEvent);
248
+ try {
249
+ if (!reqEvent.dst) {
250
+ log2.debug("\u8C03\u7528\u4E3B\u7EBF\u7A0B\u670D\u52A1");
251
+ const { api, params } = reqEvent;
252
+ const service = this.getService(api);
253
+ if (service == null) {
254
+ throw new Error(`\u4E3B\u7EBF\u7A0B\u670D\u52A1\u65E0\u6CD5\u627E\u5230: ${api}`);
255
+ }
256
+ const result = await service(...params);
257
+ const resEvent = createResEvent(reqEvent, {
258
+ result
259
+ });
260
+ log2.debug(resChannel2, resEvent);
261
+ return resEvent;
262
+ }
263
+ log2.debug("\u8C03\u7528\u6E32\u67D3\u7EBF\u7A0B\u670D\u52A1");
264
+ const webContents = this.getWebContents(reqEvent);
265
+ webContents.send(reqChannel2, reqEvent);
266
+ const resolver = Promise.withResolvers();
267
+ this.resolvers.set(reqEvent.id, resolver);
268
+ return resolver.promise;
269
+ } catch (error) {
270
+ const resEvent = createResEvent(reqEvent, {
271
+ error: toErrorObject2(error)
272
+ });
273
+ log2.debug(resChannel2, resEvent);
274
+ return resEvent;
275
+ }
276
+ });
277
+ import_electron2.ipcMain.addListener(resChannel2, (event, resEvent) => {
278
+ log2.debug(resChannel2, resEvent);
279
+ checkResEvent(resEvent);
280
+ const resolver = this.resolvers.get(resEvent.id);
281
+ if (resolver == null) {
282
+ throw new Error(`\u8BF7\u6C42\u65E0\u6CD5\u627E\u5230: ${resEvent.id}`);
283
+ }
284
+ this.resolvers.delete(resEvent.id);
285
+ resolver.resolve(resEvent);
286
+ });
287
+ }
288
+ };
289
+ // Annotate the CommonJS export names for ESM import in node:
290
+ 0 && (module.exports = {
291
+ Main,
292
+ Preload
293
+ });
294
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../main/index.ts","../main/Preload.ts","../main/Base.ts","../main/reqEvent.ts","../main/resEvent.ts","../main/Main.ts"],"sourcesContent":["import {\r\n type ServiceReqEvent,\r\n} from './reqEvent'\r\nimport {\r\n type Service,\r\n} from './Base'\r\n\r\nexport {\r\n Preload\r\n} from './Preload'\r\nexport {\r\n Main\r\n} from './Main'\r\n\r\n/**\r\n * 暴露接口类型\r\n */\r\nexport type ExposeApi = {\r\n /**\r\n * 调用服务\r\n * @param reqEvent \r\n * @returns \r\n */\r\n invoke: (reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>) => Promise<any>\r\n \r\n /**\r\n * 添加服务\r\n * @param api \r\n * @param service \r\n * @returns \r\n */\r\n addService: (api: string, service: Service) => void\r\n\r\n /**\r\n * 添加服务\r\n * @param services \r\n * @returns \r\n */\r\n addServices: (services: Record<string, Service>) => void\r\n}\r\n","import { ipcRenderer } from 'electron'\r\nimport { Base } from './Base'\r\nimport { \r\n checkReqEvent, \r\n createReqEvent,\r\n type ServiceReqEvent, \r\n} from './reqEvent'\r\nimport {\r\n createResEvent,\r\n} from './resEvent'\r\n\r\n/**\r\n * 预加载脚本\r\n */\r\nexport class Preload extends Base {\r\n\r\n async invoke(reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>) {\r\n const {\r\n log,\r\n reqChannel,\r\n resChannel,\r\n } = this.config\r\n\r\n reqEvent = createReqEvent(reqEvent)\r\n log.debug(reqChannel, reqEvent)\r\n\r\n const resEvent = await ipcRenderer.invoke(reqChannel, reqEvent)\r\n log.debug(resChannel, resEvent, {endAt: Date.now()})\r\n\r\n return resEvent.error || resEvent.result\r\n }\r\n\r\n override doInit(): void {\r\n const {\r\n log,\r\n reqChannel, \r\n resChannel,\r\n toErrorObject\r\n } = this.config\r\n\r\n // 处理请求\r\n ipcRenderer.addListener(reqChannel, async (\r\n event: Electron.IpcRendererEvent, \r\n reqEvent: ServiceReqEvent\r\n ) => {\r\n log.debug(reqChannel, reqEvent)\r\n checkReqEvent(reqEvent)\r\n\r\n const resEvent = createResEvent(reqEvent, {})\r\n try {\r\n const service = this.getService(reqEvent.api)\r\n if (service == null) {\r\n throw new Error(`客户端服务无法找到: ${reqEvent.api}`)\r\n }\r\n \r\n resEvent.result = await service(...reqEvent.params)\r\n }\r\n catch(error) {\r\n resEvent.error = toErrorObject(error)\r\n }\r\n \r\n ipcRenderer.send(resChannel, resEvent)\r\n log.debug(resChannel, resEvent)\r\n })\r\n }\r\n}","/**\r\n * 服务函数类型\r\n */\r\nexport type Service = (...params: Array<any>) => Promise<any>\r\n\r\n/**\r\n * 错误转对象方法\r\n */\r\ntype ToErrorObjectFn = (obj: any) => any\r\n\r\n/**\r\n * 打印日志方法\r\n */\r\ntype LogFn = (...args: Array<any>) => void\r\n\r\n/**\r\n * 默认错误转对象方法\r\n * @param obj \r\n * @returns \r\n */\r\nexport const toErrorObject = (obj: any): any => {\r\n if (obj instanceof Error) {\r\n const result: any = {\r\n error: obj.name,\r\n stack: obj.stack,\r\n cause: obj.cause,\r\n message: obj.message,\r\n }\r\n if ('extras' in obj) {\r\n result.extras = obj['extras']\r\n }\r\n return result\r\n }\r\n return obj\r\n}\r\n\r\n/**\r\n * 默认日志方法\r\n * @param args \r\n */\r\nconst log = function(...args: Array<any>) {\r\n console.log(...args)\r\n}\r\n\r\n/**\r\n * 配置类型\r\n */\r\nexport type Config = {\r\n reqChannel: string\r\n resChannel: string\r\n toErrorObject: ToErrorObjectFn\r\n log: {\r\n trace: LogFn,\r\n debug: LogFn,\r\n info: LogFn,\r\n warn: LogFn,\r\n error: LogFn,\r\n }\r\n}\r\n\r\n/**\r\n * 默认配置\r\n */\r\nconst reqChannel = 'runService:req'\r\nconst resChannel = 'runService:res'\r\nconst defaultConfig = {\r\n reqChannel,\r\n resChannel,\r\n toErrorObject,\r\n log: {\r\n trace: log,\r\n debug: log,\r\n info: log,\r\n warn: log,\r\n error: log,\r\n }\r\n}\r\n\r\nexport class Base {\r\n private inited = false\r\n private readonly services = new Map<string, Service>()\r\n protected readonly config: Config\r\n\r\n constructor(config?: Partial<Config>) {\r\n this.config = Object.assign({}, defaultConfig, config)\r\n }\r\n\r\n /**\r\n * 获取服务\r\n * @param key \r\n * @returns \r\n */\r\n getService(key: string): Service | undefined {\r\n return this.services.get(key)\r\n }\r\n\r\n /**\r\n * 添加服务\r\n * @param key \r\n * @param service \r\n */\r\n addService(key: string, service: Service): void {\r\n this.services.set(key, service)\r\n }\r\n\r\n /**\r\n * 添加多个服务\r\n * @param services \r\n */\r\n addServices(services: Record<string, Service>): void {\r\n Object.entries(services)\r\n .forEach(([key, service]) => {\r\n this.addService(key, service)\r\n })\r\n }\r\n\r\n /**\r\n * 删除服务\r\n * @param key \r\n */\r\n delService(key: string): void {\r\n this.services.delete(key)\r\n }\r\n\r\n /**\r\n * 初始化\r\n * @returns \r\n */\r\n init(): void {\r\n if (this.inited) {\r\n return\r\n }\r\n this.inited = true\r\n\r\n // 安装基础设施\r\n this.doInit()\r\n }\r\n\r\n protected doInit(): void {\r\n return\r\n }\r\n\r\n}","import z from 'zod'\r\n\r\n/**\r\n * 服务请求定义\r\n */\r\nconst ServiceReqEventSchema = z.object({\r\n id: z.string(),\r\n api: z.string(),\r\n dst: z.string(),\r\n src: z.string(),\r\n params: z.array(z.any()),\r\n reqAt: z.number(),\r\n})\r\n\r\n/**\r\n * 服务请求类型\r\n */\r\nexport type ServiceReqEvent = z.infer<typeof ServiceReqEventSchema>\r\n\r\n/**\r\n * 创建标识\r\n * @returns \r\n */\r\nexport function generateId(): string {\r\n const prefix = Date.now().toString(36)\r\n const suffix = Math.random().toString(36).substring(2, 6)\r\n return `${prefix}:${suffix}`\r\n}\r\n\r\n/**\r\n * 创建服务请求\r\n * @param event \r\n * @returns \r\n */\r\nexport function createReqEvent(\r\n event: Omit<ServiceReqEvent, 'id' | 'reqAt'>\r\n): ServiceReqEvent {\r\n const id = generateId()\r\n return {\r\n ...event,\r\n id, \r\n reqAt: Date.now()\r\n }\r\n}\r\n\r\n/**\r\n * 检查服务请求\r\n * @param event \r\n */\r\nexport function checkReqEvent(event: any): void {\r\n ServiceReqEventSchema.parse(event)\r\n}","import z from 'zod'\r\nimport type { ServiceReqEvent } from './reqEvent'\r\n\r\n/**\r\n * 服务响应定义\r\n */\r\nconst ServiceResEventSchema = z.object({\r\n id: z.string(),\r\n api: z.string(),\r\n dst: z.string(),\r\n src: z.string(),\r\n error: z.object({\r\n error: z.string(),\r\n message: z.string(),\r\n stack: z.string().optional(),\r\n extras: z.any().optional()\r\n }).optional(),\r\n result: z.any().optional(),\r\n reqAt: z.number(),\r\n resAt: z.number(),\r\n})\r\n\r\n/**\r\n * 服务响应类型\r\n */\r\nexport type ServiceResEvent = z.infer<typeof ServiceResEventSchema>\r\n\r\n/**\r\n * 创建服务响应\r\n * @param reqEvent \r\n * @param resEvent \r\n * @returns \r\n */\r\nexport function createResEvent(\r\n reqEvent: ServiceReqEvent, \r\n resEvent: Pick<ServiceResEvent, 'error' | 'result'>\r\n): ServiceResEvent {\r\n const { \r\n id, \r\n api, \r\n dst: src, \r\n src: dst, \r\n reqAt \r\n } = reqEvent\r\n return {\r\n ...resEvent,\r\n id,\r\n api,\r\n dst,\r\n src,\r\n reqAt,\r\n resAt: Date.now(),\r\n }\r\n}\r\n\r\n/**\r\n * 检查服务响应\r\n * @param event \r\n */\r\nexport function checkResEvent(event: object): void {\r\n ServiceResEventSchema.parse(event)\r\n}","import { \r\n type WebContents, \r\n ipcMain, \r\n} from 'electron'\r\nimport { Base } from './Base'\r\nimport { \r\n type ServiceReqEvent, \r\n checkReqEvent, \r\n} from './reqEvent'\r\nimport {\r\n type ServiceResEvent,\r\n checkResEvent,\r\n createResEvent\r\n} from './resEvent'\r\n\r\n/**\r\n * 主线程脚本\r\n */\r\nexport abstract class Main extends Base {\r\n private readonly resolvers = new Map<string, PromiseWithResolvers<any>>()\r\n\r\n /**\r\n * 获取网页对象\r\n * @param reqEvent \r\n */\r\n protected abstract getWebContents(reqEvent: ServiceReqEvent): WebContents\r\n\r\n doInit(): void {\r\n const {\r\n log,\r\n reqChannel, \r\n resChannel,\r\n toErrorObject\r\n } = this.config\r\n\r\n // 转发请求\r\n ipcMain.handle(reqChannel, async (\r\n event: Electron.IpcMainInvokeEvent, \r\n reqEvent: ServiceReqEvent\r\n ) => {\r\n log.debug(reqChannel, reqEvent)\r\n checkReqEvent(reqEvent)\r\n\r\n try {\r\n // 主线程\r\n if (!reqEvent.dst) {\r\n log.debug('调用主线程服务')\r\n \r\n const { api, params } = reqEvent\r\n const service = this.getService(api)\r\n if (service == null) {\r\n throw new Error(`主线程服务无法找到: ${api}`)\r\n }\r\n \r\n const result = await service(...params)\r\n const resEvent = createResEvent(reqEvent, {\r\n result,\r\n })\r\n log.debug(resChannel, resEvent)\r\n return resEvent\r\n }\r\n \r\n // 渲染线程\r\n log.debug('调用渲染线程服务')\r\n \r\n // 转发请求\r\n const webContents = this.getWebContents(reqEvent)\r\n webContents.send(reqChannel, reqEvent)\r\n \r\n const resolver = Promise.withResolvers<any>()\r\n this.resolvers.set(reqEvent.id, resolver)\r\n return resolver.promise\r\n }\r\n catch(error) {\r\n const resEvent = createResEvent(reqEvent, {\r\n error: toErrorObject(error),\r\n })\r\n log.debug(resChannel, resEvent)\r\n return resEvent\r\n }\r\n })\r\n \r\n // 转发响应\r\n ipcMain.addListener(resChannel, (\r\n event: Electron.IpcMainEvent, \r\n resEvent: ServiceResEvent\r\n ) => {\r\n log.debug(resChannel, resEvent)\r\n checkResEvent(resEvent)\r\n\r\n const resolver = this.resolvers.get(resEvent.id)\r\n if (resolver == null) {\r\n throw new Error(`请求无法找到: ${resEvent.id}`)\r\n }\r\n\r\n this.resolvers.delete(resEvent.id)\r\n resolver.resolve(resEvent)\r\n })\r\n }\r\n}"],"mappings":"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","names":["z","import_zod","z","log","reqChannel","resChannel","toErrorObject","import_electron","log","reqChannel","resChannel","toErrorObject"]}
@@ -0,0 +1,128 @@
1
+ import z from 'zod';
2
+ import { WebContents } from 'electron';
3
+
4
+ /**
5
+ * 服务请求定义
6
+ */
7
+ declare const ServiceReqEventSchema: z.ZodObject<{
8
+ id: z.ZodString;
9
+ api: z.ZodString;
10
+ dst: z.ZodString;
11
+ src: z.ZodString;
12
+ params: z.ZodArray<z.ZodAny>;
13
+ reqAt: z.ZodNumber;
14
+ }, z.core.$strip>;
15
+ /**
16
+ * 服务请求类型
17
+ */
18
+ type ServiceReqEvent = z.infer<typeof ServiceReqEventSchema>;
19
+
20
+ /**
21
+ * 服务函数类型
22
+ */
23
+ type Service = (...params: Array<any>) => Promise<any>;
24
+ /**
25
+ * 错误转对象方法
26
+ */
27
+ type ToErrorObjectFn = (obj: any) => any;
28
+ /**
29
+ * 打印日志方法
30
+ */
31
+ type LogFn = (...args: Array<any>) => void;
32
+ /**
33
+ * 配置类型
34
+ */
35
+ type Config = {
36
+ reqChannel: string;
37
+ resChannel: string;
38
+ toErrorObject: ToErrorObjectFn;
39
+ log: {
40
+ trace: LogFn;
41
+ debug: LogFn;
42
+ info: LogFn;
43
+ warn: LogFn;
44
+ error: LogFn;
45
+ };
46
+ };
47
+ declare class Base {
48
+ private inited;
49
+ private readonly services;
50
+ protected readonly config: Config;
51
+ constructor(config?: Partial<Config>);
52
+ /**
53
+ * 获取服务
54
+ * @param key
55
+ * @returns
56
+ */
57
+ getService(key: string): Service | undefined;
58
+ /**
59
+ * 添加服务
60
+ * @param key
61
+ * @param service
62
+ */
63
+ addService(key: string, service: Service): void;
64
+ /**
65
+ * 添加多个服务
66
+ * @param services
67
+ */
68
+ addServices(services: Record<string, Service>): void;
69
+ /**
70
+ * 删除服务
71
+ * @param key
72
+ */
73
+ delService(key: string): void;
74
+ /**
75
+ * 初始化
76
+ * @returns
77
+ */
78
+ init(): void;
79
+ protected doInit(): void;
80
+ }
81
+
82
+ /**
83
+ * 预加载脚本
84
+ */
85
+ declare class Preload extends Base {
86
+ invoke(reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>): Promise<any>;
87
+ doInit(): void;
88
+ }
89
+
90
+ /**
91
+ * 主线程脚本
92
+ */
93
+ declare abstract class Main extends Base {
94
+ private readonly resolvers;
95
+ /**
96
+ * 获取网页对象
97
+ * @param reqEvent
98
+ */
99
+ protected abstract getWebContents(reqEvent: ServiceReqEvent): WebContents;
100
+ doInit(): void;
101
+ }
102
+
103
+ /**
104
+ * 暴露接口类型
105
+ */
106
+ type ExposeApi = {
107
+ /**
108
+ * 调用服务
109
+ * @param reqEvent
110
+ * @returns
111
+ */
112
+ invoke: (reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>) => Promise<any>;
113
+ /**
114
+ * 添加服务
115
+ * @param api
116
+ * @param service
117
+ * @returns
118
+ */
119
+ addService: (api: string, service: Service) => void;
120
+ /**
121
+ * 添加服务
122
+ * @param services
123
+ * @returns
124
+ */
125
+ addServices: (services: Record<string, Service>) => void;
126
+ };
127
+
128
+ export { type ExposeApi, Main, Preload };
@@ -0,0 +1,128 @@
1
+ import z from 'zod';
2
+ import { WebContents } from 'electron';
3
+
4
+ /**
5
+ * 服务请求定义
6
+ */
7
+ declare const ServiceReqEventSchema: z.ZodObject<{
8
+ id: z.ZodString;
9
+ api: z.ZodString;
10
+ dst: z.ZodString;
11
+ src: z.ZodString;
12
+ params: z.ZodArray<z.ZodAny>;
13
+ reqAt: z.ZodNumber;
14
+ }, z.core.$strip>;
15
+ /**
16
+ * 服务请求类型
17
+ */
18
+ type ServiceReqEvent = z.infer<typeof ServiceReqEventSchema>;
19
+
20
+ /**
21
+ * 服务函数类型
22
+ */
23
+ type Service = (...params: Array<any>) => Promise<any>;
24
+ /**
25
+ * 错误转对象方法
26
+ */
27
+ type ToErrorObjectFn = (obj: any) => any;
28
+ /**
29
+ * 打印日志方法
30
+ */
31
+ type LogFn = (...args: Array<any>) => void;
32
+ /**
33
+ * 配置类型
34
+ */
35
+ type Config = {
36
+ reqChannel: string;
37
+ resChannel: string;
38
+ toErrorObject: ToErrorObjectFn;
39
+ log: {
40
+ trace: LogFn;
41
+ debug: LogFn;
42
+ info: LogFn;
43
+ warn: LogFn;
44
+ error: LogFn;
45
+ };
46
+ };
47
+ declare class Base {
48
+ private inited;
49
+ private readonly services;
50
+ protected readonly config: Config;
51
+ constructor(config?: Partial<Config>);
52
+ /**
53
+ * 获取服务
54
+ * @param key
55
+ * @returns
56
+ */
57
+ getService(key: string): Service | undefined;
58
+ /**
59
+ * 添加服务
60
+ * @param key
61
+ * @param service
62
+ */
63
+ addService(key: string, service: Service): void;
64
+ /**
65
+ * 添加多个服务
66
+ * @param services
67
+ */
68
+ addServices(services: Record<string, Service>): void;
69
+ /**
70
+ * 删除服务
71
+ * @param key
72
+ */
73
+ delService(key: string): void;
74
+ /**
75
+ * 初始化
76
+ * @returns
77
+ */
78
+ init(): void;
79
+ protected doInit(): void;
80
+ }
81
+
82
+ /**
83
+ * 预加载脚本
84
+ */
85
+ declare class Preload extends Base {
86
+ invoke(reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>): Promise<any>;
87
+ doInit(): void;
88
+ }
89
+
90
+ /**
91
+ * 主线程脚本
92
+ */
93
+ declare abstract class Main extends Base {
94
+ private readonly resolvers;
95
+ /**
96
+ * 获取网页对象
97
+ * @param reqEvent
98
+ */
99
+ protected abstract getWebContents(reqEvent: ServiceReqEvent): WebContents;
100
+ doInit(): void;
101
+ }
102
+
103
+ /**
104
+ * 暴露接口类型
105
+ */
106
+ type ExposeApi = {
107
+ /**
108
+ * 调用服务
109
+ * @param reqEvent
110
+ * @returns
111
+ */
112
+ invoke: (reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>) => Promise<any>;
113
+ /**
114
+ * 添加服务
115
+ * @param api
116
+ * @param service
117
+ * @returns
118
+ */
119
+ addService: (api: string, service: Service) => void;
120
+ /**
121
+ * 添加服务
122
+ * @param services
123
+ * @returns
124
+ */
125
+ addServices: (services: Record<string, Service>) => void;
126
+ };
127
+
128
+ export { type ExposeApi, Main, Preload };
package/dist/index.mjs ADDED
@@ -0,0 +1,259 @@
1
+ // main/Preload.ts
2
+ import { ipcRenderer } from "electron";
3
+
4
+ // main/Base.ts
5
+ var toErrorObject = (obj) => {
6
+ if (obj instanceof Error) {
7
+ const result = {
8
+ error: obj.name,
9
+ stack: obj.stack,
10
+ cause: obj.cause,
11
+ message: obj.message
12
+ };
13
+ if ("extras" in obj) {
14
+ result.extras = obj["extras"];
15
+ }
16
+ return result;
17
+ }
18
+ return obj;
19
+ };
20
+ var log = function(...args) {
21
+ console.log(...args);
22
+ };
23
+ var reqChannel = "runService:req";
24
+ var resChannel = "runService:res";
25
+ var defaultConfig = {
26
+ reqChannel,
27
+ resChannel,
28
+ toErrorObject,
29
+ log: {
30
+ trace: log,
31
+ debug: log,
32
+ info: log,
33
+ warn: log,
34
+ error: log
35
+ }
36
+ };
37
+ var Base = class {
38
+ inited = false;
39
+ services = /* @__PURE__ */ new Map();
40
+ config;
41
+ constructor(config) {
42
+ this.config = Object.assign({}, defaultConfig, config);
43
+ }
44
+ /**
45
+ * 获取服务
46
+ * @param key
47
+ * @returns
48
+ */
49
+ getService(key) {
50
+ return this.services.get(key);
51
+ }
52
+ /**
53
+ * 添加服务
54
+ * @param key
55
+ * @param service
56
+ */
57
+ addService(key, service) {
58
+ this.services.set(key, service);
59
+ }
60
+ /**
61
+ * 添加多个服务
62
+ * @param services
63
+ */
64
+ addServices(services) {
65
+ Object.entries(services).forEach(([key, service]) => {
66
+ this.addService(key, service);
67
+ });
68
+ }
69
+ /**
70
+ * 删除服务
71
+ * @param key
72
+ */
73
+ delService(key) {
74
+ this.services.delete(key);
75
+ }
76
+ /**
77
+ * 初始化
78
+ * @returns
79
+ */
80
+ init() {
81
+ if (this.inited) {
82
+ return;
83
+ }
84
+ this.inited = true;
85
+ this.doInit();
86
+ }
87
+ doInit() {
88
+ return;
89
+ }
90
+ };
91
+
92
+ // main/reqEvent.ts
93
+ import z from "zod";
94
+ var ServiceReqEventSchema = z.object({
95
+ id: z.string(),
96
+ api: z.string(),
97
+ dst: z.string(),
98
+ src: z.string(),
99
+ params: z.array(z.any()),
100
+ reqAt: z.number()
101
+ });
102
+ function generateId() {
103
+ const prefix = Date.now().toString(36);
104
+ const suffix = Math.random().toString(36).substring(2, 6);
105
+ return `${prefix}:${suffix}`;
106
+ }
107
+ function createReqEvent(event) {
108
+ const id = generateId();
109
+ return {
110
+ ...event,
111
+ id,
112
+ reqAt: Date.now()
113
+ };
114
+ }
115
+ function checkReqEvent(event) {
116
+ ServiceReqEventSchema.parse(event);
117
+ }
118
+
119
+ // main/resEvent.ts
120
+ import z2 from "zod";
121
+ var ServiceResEventSchema = z2.object({
122
+ id: z2.string(),
123
+ api: z2.string(),
124
+ dst: z2.string(),
125
+ src: z2.string(),
126
+ error: z2.object({
127
+ error: z2.string(),
128
+ message: z2.string(),
129
+ stack: z2.string().optional(),
130
+ extras: z2.any().optional()
131
+ }).optional(),
132
+ result: z2.any().optional(),
133
+ reqAt: z2.number(),
134
+ resAt: z2.number()
135
+ });
136
+ function createResEvent(reqEvent, resEvent) {
137
+ const {
138
+ id,
139
+ api,
140
+ dst: src,
141
+ src: dst,
142
+ reqAt
143
+ } = reqEvent;
144
+ return {
145
+ ...resEvent,
146
+ id,
147
+ api,
148
+ dst,
149
+ src,
150
+ reqAt,
151
+ resAt: Date.now()
152
+ };
153
+ }
154
+ function checkResEvent(event) {
155
+ ServiceResEventSchema.parse(event);
156
+ }
157
+
158
+ // main/Preload.ts
159
+ var Preload = class extends Base {
160
+ async invoke(reqEvent) {
161
+ const {
162
+ log: log2,
163
+ reqChannel: reqChannel2,
164
+ resChannel: resChannel2
165
+ } = this.config;
166
+ reqEvent = createReqEvent(reqEvent);
167
+ log2.debug(reqChannel2, reqEvent);
168
+ const resEvent = await ipcRenderer.invoke(reqChannel2, reqEvent);
169
+ log2.debug(resChannel2, resEvent, { endAt: Date.now() });
170
+ return resEvent.error || resEvent.result;
171
+ }
172
+ doInit() {
173
+ const {
174
+ log: log2,
175
+ reqChannel: reqChannel2,
176
+ resChannel: resChannel2,
177
+ toErrorObject: toErrorObject2
178
+ } = this.config;
179
+ ipcRenderer.addListener(reqChannel2, async (event, reqEvent) => {
180
+ log2.debug(reqChannel2, reqEvent);
181
+ checkReqEvent(reqEvent);
182
+ const resEvent = createResEvent(reqEvent, {});
183
+ try {
184
+ const service = this.getService(reqEvent.api);
185
+ if (service == null) {
186
+ throw new Error(`\u5BA2\u6237\u7AEF\u670D\u52A1\u65E0\u6CD5\u627E\u5230: ${reqEvent.api}`);
187
+ }
188
+ resEvent.result = await service(...reqEvent.params);
189
+ } catch (error) {
190
+ resEvent.error = toErrorObject2(error);
191
+ }
192
+ ipcRenderer.send(resChannel2, resEvent);
193
+ log2.debug(resChannel2, resEvent);
194
+ });
195
+ }
196
+ };
197
+
198
+ // main/Main.ts
199
+ import {
200
+ ipcMain
201
+ } from "electron";
202
+ var Main = class extends Base {
203
+ resolvers = /* @__PURE__ */ new Map();
204
+ doInit() {
205
+ const {
206
+ log: log2,
207
+ reqChannel: reqChannel2,
208
+ resChannel: resChannel2,
209
+ toErrorObject: toErrorObject2
210
+ } = this.config;
211
+ ipcMain.handle(reqChannel2, async (event, reqEvent) => {
212
+ log2.debug(reqChannel2, reqEvent);
213
+ checkReqEvent(reqEvent);
214
+ try {
215
+ if (!reqEvent.dst) {
216
+ log2.debug("\u8C03\u7528\u4E3B\u7EBF\u7A0B\u670D\u52A1");
217
+ const { api, params } = reqEvent;
218
+ const service = this.getService(api);
219
+ if (service == null) {
220
+ throw new Error(`\u4E3B\u7EBF\u7A0B\u670D\u52A1\u65E0\u6CD5\u627E\u5230: ${api}`);
221
+ }
222
+ const result = await service(...params);
223
+ const resEvent = createResEvent(reqEvent, {
224
+ result
225
+ });
226
+ log2.debug(resChannel2, resEvent);
227
+ return resEvent;
228
+ }
229
+ log2.debug("\u8C03\u7528\u6E32\u67D3\u7EBF\u7A0B\u670D\u52A1");
230
+ const webContents = this.getWebContents(reqEvent);
231
+ webContents.send(reqChannel2, reqEvent);
232
+ const resolver = Promise.withResolvers();
233
+ this.resolvers.set(reqEvent.id, resolver);
234
+ return resolver.promise;
235
+ } catch (error) {
236
+ const resEvent = createResEvent(reqEvent, {
237
+ error: toErrorObject2(error)
238
+ });
239
+ log2.debug(resChannel2, resEvent);
240
+ return resEvent;
241
+ }
242
+ });
243
+ ipcMain.addListener(resChannel2, (event, resEvent) => {
244
+ log2.debug(resChannel2, resEvent);
245
+ checkResEvent(resEvent);
246
+ const resolver = this.resolvers.get(resEvent.id);
247
+ if (resolver == null) {
248
+ throw new Error(`\u8BF7\u6C42\u65E0\u6CD5\u627E\u5230: ${resEvent.id}`);
249
+ }
250
+ this.resolvers.delete(resEvent.id);
251
+ resolver.resolve(resEvent);
252
+ });
253
+ }
254
+ };
255
+ export {
256
+ Main,
257
+ Preload
258
+ };
259
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../main/Preload.ts","../main/Base.ts","../main/reqEvent.ts","../main/resEvent.ts","../main/Main.ts"],"sourcesContent":["import { ipcRenderer } from 'electron'\r\nimport { Base } from './Base'\r\nimport { \r\n checkReqEvent, \r\n createReqEvent,\r\n type ServiceReqEvent, \r\n} from './reqEvent'\r\nimport {\r\n createResEvent,\r\n} from './resEvent'\r\n\r\n/**\r\n * 预加载脚本\r\n */\r\nexport class Preload extends Base {\r\n\r\n async invoke(reqEvent: Omit<ServiceReqEvent, 'id' | 'reqAt'>) {\r\n const {\r\n log,\r\n reqChannel,\r\n resChannel,\r\n } = this.config\r\n\r\n reqEvent = createReqEvent(reqEvent)\r\n log.debug(reqChannel, reqEvent)\r\n\r\n const resEvent = await ipcRenderer.invoke(reqChannel, reqEvent)\r\n log.debug(resChannel, resEvent, {endAt: Date.now()})\r\n\r\n return resEvent.error || resEvent.result\r\n }\r\n\r\n override doInit(): void {\r\n const {\r\n log,\r\n reqChannel, \r\n resChannel,\r\n toErrorObject\r\n } = this.config\r\n\r\n // 处理请求\r\n ipcRenderer.addListener(reqChannel, async (\r\n event: Electron.IpcRendererEvent, \r\n reqEvent: ServiceReqEvent\r\n ) => {\r\n log.debug(reqChannel, reqEvent)\r\n checkReqEvent(reqEvent)\r\n\r\n const resEvent = createResEvent(reqEvent, {})\r\n try {\r\n const service = this.getService(reqEvent.api)\r\n if (service == null) {\r\n throw new Error(`客户端服务无法找到: ${reqEvent.api}`)\r\n }\r\n \r\n resEvent.result = await service(...reqEvent.params)\r\n }\r\n catch(error) {\r\n resEvent.error = toErrorObject(error)\r\n }\r\n \r\n ipcRenderer.send(resChannel, resEvent)\r\n log.debug(resChannel, resEvent)\r\n })\r\n }\r\n}","/**\r\n * 服务函数类型\r\n */\r\nexport type Service = (...params: Array<any>) => Promise<any>\r\n\r\n/**\r\n * 错误转对象方法\r\n */\r\ntype ToErrorObjectFn = (obj: any) => any\r\n\r\n/**\r\n * 打印日志方法\r\n */\r\ntype LogFn = (...args: Array<any>) => void\r\n\r\n/**\r\n * 默认错误转对象方法\r\n * @param obj \r\n * @returns \r\n */\r\nexport const toErrorObject = (obj: any): any => {\r\n if (obj instanceof Error) {\r\n const result: any = {\r\n error: obj.name,\r\n stack: obj.stack,\r\n cause: obj.cause,\r\n message: obj.message,\r\n }\r\n if ('extras' in obj) {\r\n result.extras = obj['extras']\r\n }\r\n return result\r\n }\r\n return obj\r\n}\r\n\r\n/**\r\n * 默认日志方法\r\n * @param args \r\n */\r\nconst log = function(...args: Array<any>) {\r\n console.log(...args)\r\n}\r\n\r\n/**\r\n * 配置类型\r\n */\r\nexport type Config = {\r\n reqChannel: string\r\n resChannel: string\r\n toErrorObject: ToErrorObjectFn\r\n log: {\r\n trace: LogFn,\r\n debug: LogFn,\r\n info: LogFn,\r\n warn: LogFn,\r\n error: LogFn,\r\n }\r\n}\r\n\r\n/**\r\n * 默认配置\r\n */\r\nconst reqChannel = 'runService:req'\r\nconst resChannel = 'runService:res'\r\nconst defaultConfig = {\r\n reqChannel,\r\n resChannel,\r\n toErrorObject,\r\n log: {\r\n trace: log,\r\n debug: log,\r\n info: log,\r\n warn: log,\r\n error: log,\r\n }\r\n}\r\n\r\nexport class Base {\r\n private inited = false\r\n private readonly services = new Map<string, Service>()\r\n protected readonly config: Config\r\n\r\n constructor(config?: Partial<Config>) {\r\n this.config = Object.assign({}, defaultConfig, config)\r\n }\r\n\r\n /**\r\n * 获取服务\r\n * @param key \r\n * @returns \r\n */\r\n getService(key: string): Service | undefined {\r\n return this.services.get(key)\r\n }\r\n\r\n /**\r\n * 添加服务\r\n * @param key \r\n * @param service \r\n */\r\n addService(key: string, service: Service): void {\r\n this.services.set(key, service)\r\n }\r\n\r\n /**\r\n * 添加多个服务\r\n * @param services \r\n */\r\n addServices(services: Record<string, Service>): void {\r\n Object.entries(services)\r\n .forEach(([key, service]) => {\r\n this.addService(key, service)\r\n })\r\n }\r\n\r\n /**\r\n * 删除服务\r\n * @param key \r\n */\r\n delService(key: string): void {\r\n this.services.delete(key)\r\n }\r\n\r\n /**\r\n * 初始化\r\n * @returns \r\n */\r\n init(): void {\r\n if (this.inited) {\r\n return\r\n }\r\n this.inited = true\r\n\r\n // 安装基础设施\r\n this.doInit()\r\n }\r\n\r\n protected doInit(): void {\r\n return\r\n }\r\n\r\n}","import z from 'zod'\r\n\r\n/**\r\n * 服务请求定义\r\n */\r\nconst ServiceReqEventSchema = z.object({\r\n id: z.string(),\r\n api: z.string(),\r\n dst: z.string(),\r\n src: z.string(),\r\n params: z.array(z.any()),\r\n reqAt: z.number(),\r\n})\r\n\r\n/**\r\n * 服务请求类型\r\n */\r\nexport type ServiceReqEvent = z.infer<typeof ServiceReqEventSchema>\r\n\r\n/**\r\n * 创建标识\r\n * @returns \r\n */\r\nexport function generateId(): string {\r\n const prefix = Date.now().toString(36)\r\n const suffix = Math.random().toString(36).substring(2, 6)\r\n return `${prefix}:${suffix}`\r\n}\r\n\r\n/**\r\n * 创建服务请求\r\n * @param event \r\n * @returns \r\n */\r\nexport function createReqEvent(\r\n event: Omit<ServiceReqEvent, 'id' | 'reqAt'>\r\n): ServiceReqEvent {\r\n const id = generateId()\r\n return {\r\n ...event,\r\n id, \r\n reqAt: Date.now()\r\n }\r\n}\r\n\r\n/**\r\n * 检查服务请求\r\n * @param event \r\n */\r\nexport function checkReqEvent(event: any): void {\r\n ServiceReqEventSchema.parse(event)\r\n}","import z from 'zod'\r\nimport type { ServiceReqEvent } from './reqEvent'\r\n\r\n/**\r\n * 服务响应定义\r\n */\r\nconst ServiceResEventSchema = z.object({\r\n id: z.string(),\r\n api: z.string(),\r\n dst: z.string(),\r\n src: z.string(),\r\n error: z.object({\r\n error: z.string(),\r\n message: z.string(),\r\n stack: z.string().optional(),\r\n extras: z.any().optional()\r\n }).optional(),\r\n result: z.any().optional(),\r\n reqAt: z.number(),\r\n resAt: z.number(),\r\n})\r\n\r\n/**\r\n * 服务响应类型\r\n */\r\nexport type ServiceResEvent = z.infer<typeof ServiceResEventSchema>\r\n\r\n/**\r\n * 创建服务响应\r\n * @param reqEvent \r\n * @param resEvent \r\n * @returns \r\n */\r\nexport function createResEvent(\r\n reqEvent: ServiceReqEvent, \r\n resEvent: Pick<ServiceResEvent, 'error' | 'result'>\r\n): ServiceResEvent {\r\n const { \r\n id, \r\n api, \r\n dst: src, \r\n src: dst, \r\n reqAt \r\n } = reqEvent\r\n return {\r\n ...resEvent,\r\n id,\r\n api,\r\n dst,\r\n src,\r\n reqAt,\r\n resAt: Date.now(),\r\n }\r\n}\r\n\r\n/**\r\n * 检查服务响应\r\n * @param event \r\n */\r\nexport function checkResEvent(event: object): void {\r\n ServiceResEventSchema.parse(event)\r\n}","import { \r\n type WebContents, \r\n ipcMain, \r\n} from 'electron'\r\nimport { Base } from './Base'\r\nimport { \r\n type ServiceReqEvent, \r\n checkReqEvent, \r\n} from './reqEvent'\r\nimport {\r\n type ServiceResEvent,\r\n checkResEvent,\r\n createResEvent\r\n} from './resEvent'\r\n\r\n/**\r\n * 主线程脚本\r\n */\r\nexport abstract class Main extends Base {\r\n private readonly resolvers = new Map<string, PromiseWithResolvers<any>>()\r\n\r\n /**\r\n * 获取网页对象\r\n * @param reqEvent \r\n */\r\n protected abstract getWebContents(reqEvent: ServiceReqEvent): WebContents\r\n\r\n doInit(): void {\r\n const {\r\n log,\r\n reqChannel, \r\n resChannel,\r\n toErrorObject\r\n } = this.config\r\n\r\n // 转发请求\r\n ipcMain.handle(reqChannel, async (\r\n event: Electron.IpcMainInvokeEvent, \r\n reqEvent: ServiceReqEvent\r\n ) => {\r\n log.debug(reqChannel, reqEvent)\r\n checkReqEvent(reqEvent)\r\n\r\n try {\r\n // 主线程\r\n if (!reqEvent.dst) {\r\n log.debug('调用主线程服务')\r\n \r\n const { api, params } = reqEvent\r\n const service = this.getService(api)\r\n if (service == null) {\r\n throw new Error(`主线程服务无法找到: ${api}`)\r\n }\r\n \r\n const result = await service(...params)\r\n const resEvent = createResEvent(reqEvent, {\r\n result,\r\n })\r\n log.debug(resChannel, resEvent)\r\n return resEvent\r\n }\r\n \r\n // 渲染线程\r\n log.debug('调用渲染线程服务')\r\n \r\n // 转发请求\r\n const webContents = this.getWebContents(reqEvent)\r\n webContents.send(reqChannel, reqEvent)\r\n \r\n const resolver = Promise.withResolvers<any>()\r\n this.resolvers.set(reqEvent.id, resolver)\r\n return resolver.promise\r\n }\r\n catch(error) {\r\n const resEvent = createResEvent(reqEvent, {\r\n error: toErrorObject(error),\r\n })\r\n log.debug(resChannel, resEvent)\r\n return resEvent\r\n }\r\n })\r\n \r\n // 转发响应\r\n ipcMain.addListener(resChannel, (\r\n event: Electron.IpcMainEvent, \r\n resEvent: ServiceResEvent\r\n ) => {\r\n log.debug(resChannel, resEvent)\r\n checkResEvent(resEvent)\r\n\r\n const resolver = this.resolvers.get(resEvent.id)\r\n if (resolver == null) {\r\n throw new Error(`请求无法找到: ${resEvent.id}`)\r\n }\r\n\r\n this.resolvers.delete(resEvent.id)\r\n resolver.resolve(resEvent)\r\n })\r\n }\r\n}"],"mappings":"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","names":["z","log","reqChannel","resChannel","toErrorObject","log","reqChannel","resChannel","toErrorObject"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@chenpeiyuan/electron-message",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org/",
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "prebuild": "rimraf dist .tsbuildinfo",
24
+ "build": "tsup",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest"
27
+ },
28
+ "keywords": [],
29
+ "author": "",
30
+ "license": "ISC",
31
+ "packageManager": "pnpm@10.12.4",
32
+ "dependencies": {
33
+ "zod": "^4.3.6"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^24.9.2",
37
+ "cross-env": "^10.1.0",
38
+ "electron": "^40.4.1",
39
+ "rimraf": "^6.0.1",
40
+ "tsc-alias": "^1.8.16",
41
+ "tsup": "^8.5.0",
42
+ "tsx": "^4.20.6",
43
+ "typescript": "^5.9.3",
44
+ "vitest": "^4.0.4"
45
+ },
46
+ "peerDependencies": {
47
+ "electron": "^40.4.1"
48
+ }
49
+ }