@aiot-nexus/plugin-sdk 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -8
- package/dev-host/main.js +134 -7
- package/dev-host/plugin-host.js +1 -427
- package/dist/.generated/plugin-framework-version.d.ts +1 -1
- package/dist/.generated/plugin-framework-version.js +1 -1
- package/dist/.generated/plugin-manifest.schema.json +1 -1
- package/dist/internal/src-electron/main/core/runtime-result.js +42 -0
- package/dist/internal/src-electron/main/plugins/plugin-electron-facade-broker.js +890 -0
- package/dist/internal/src-electron/plugin-host-bootstrap.js +417 -0
- package/dist/internal/src-electron/shared/contracts.js +2 -0
- package/dist/internal/src-electron/shared/plugin-electron-facade-client.js +181 -0
- package/dist/internal/src-electron/shared/plugin-electron-facade-descriptors.js +70 -0
- package/dist/internal/src-electron/shared/plugin-electron-facade.js +243 -0
- package/dist/internal/src-electron/shared/plugin-rpc.js +245 -0
- package/dist/src/electron-facade.d.ts +4 -0
- package/dist/src/electron-facade.js +56 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/dist/src/nexus-dev.js +5 -4
- package/dist/src/scaffold.js +2 -2
- package/dist/src/types.d.ts +86 -2
- package/dist/src/web-dev.js +2 -2
- package/package.json +7 -2
- package/templates/minimal/README.md.tmpl +35 -2
- package/templates/minimal/src/main.ts.tmpl +2 -1
- package/templates/sqlite/README.md.tmpl +30 -2
- package/templates/sqlite/src/better-sqlite3.d.ts +12 -1
- package/templates/sqlite/src/main.ts.tmpl +939 -124
- package/templates/sqlite/src/renderer/app.ts.tmpl +688 -181
- package/templates/sqlite/src/renderer/index.html +40 -22
- package/templates/sqlite/src/renderer/plugin.css +302 -90
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.runPluginHostBootstrap = exports.pluginHostBootstrapProtocolVersion = void 0;
|
|
27
|
+
const path = __importStar(require("path"));
|
|
28
|
+
const plugin_rpc_1 = require("./shared/plugin-rpc");
|
|
29
|
+
const plugin_electron_facade_client_1 = require("./shared/plugin-electron-facade-client");
|
|
30
|
+
const implementedPermissions = new Set(["businessLog", "settings"]);
|
|
31
|
+
const hostControlPermissions = new Set(["electronHostControl"]);
|
|
32
|
+
const routeGuardPermissions = new Set(["filesystem", "udp", "serial", "dialog"]);
|
|
33
|
+
exports.pluginHostBootstrapProtocolVersion = plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION;
|
|
34
|
+
function runPluginHostBootstrap(port, options = {}) {
|
|
35
|
+
if (!port) {
|
|
36
|
+
return () => undefined;
|
|
37
|
+
}
|
|
38
|
+
const controller = new PluginHostController(port, options);
|
|
39
|
+
controller.start();
|
|
40
|
+
return () => controller.dispose();
|
|
41
|
+
}
|
|
42
|
+
exports.runPluginHostBootstrap = runPluginHostBootstrap;
|
|
43
|
+
class PluginHostController {
|
|
44
|
+
constructor(port, options) {
|
|
45
|
+
this.port = port;
|
|
46
|
+
this.operations = new Map();
|
|
47
|
+
this.pendingHostRequests = new Map();
|
|
48
|
+
this.inFlightOperations = new Set();
|
|
49
|
+
this.initialized = false;
|
|
50
|
+
this.ready = false;
|
|
51
|
+
this.shuttingDown = false;
|
|
52
|
+
this.exiting = false;
|
|
53
|
+
this.pluginId = "";
|
|
54
|
+
this.pluginDirectory = "";
|
|
55
|
+
this.pluginDataDirectory = "";
|
|
56
|
+
this.hostVersion = "";
|
|
57
|
+
this.hostApiVersion = "";
|
|
58
|
+
this.requestSequence = 0;
|
|
59
|
+
this.now = options.now || (() => new Date().toISOString());
|
|
60
|
+
this.exit = options.exit || ((code) => process.exit(code));
|
|
61
|
+
this.requireModule = options.requireModule || loadPluginMainModule;
|
|
62
|
+
this.installProcessHandlers = options.installProcessHandlers === true;
|
|
63
|
+
this.messageListener = (event) => {
|
|
64
|
+
void this.handleMessage(readMessageData(event));
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
start() {
|
|
68
|
+
this.port.on("message", this.messageListener);
|
|
69
|
+
if (this.installProcessHandlers) {
|
|
70
|
+
process.once("uncaughtException", (error) => {
|
|
71
|
+
this.failProcess(error instanceof Error ? error.message : String(error));
|
|
72
|
+
});
|
|
73
|
+
process.once("unhandledRejection", (reason) => {
|
|
74
|
+
this.failProcess(reason instanceof Error ? reason.message : String(reason));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
dispose() {
|
|
79
|
+
this.port.removeListener?.("message", this.messageListener);
|
|
80
|
+
const error = createPluginRpcFailure(plugin_rpc_1.PluginRpcErrorCodes.ProcessExited, "Plugin host process stopped.");
|
|
81
|
+
for (const pending of this.pendingHostRequests.values()) {
|
|
82
|
+
pending.resolve(error);
|
|
83
|
+
}
|
|
84
|
+
this.pendingHostRequests.clear();
|
|
85
|
+
this.electronFacadeClient?.dispose();
|
|
86
|
+
this.electronFacadeClient = undefined;
|
|
87
|
+
}
|
|
88
|
+
async handleMessage(message) {
|
|
89
|
+
if (this.exiting) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!(0, plugin_rpc_1.isPluginRpcMessage)(message)) {
|
|
93
|
+
this.failProcess("Plugin RPC message is invalid.");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (message.type === "initialize") {
|
|
97
|
+
await this.handleInitialize(message);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (message.type === "hostResult") {
|
|
101
|
+
this.handleHostResult(message.requestId, message.result);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (message.type === "electronCallback") {
|
|
105
|
+
await this.handleElectronCallback(message.requestId, message.payload.callbackId, message.payload.args);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (message.type === "electronEvent") {
|
|
109
|
+
this.electronFacadeClient?.emitEvent(message.payload.callbackId, message.payload.args);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (message.type === "invoke") {
|
|
113
|
+
await this.handleTrackedInvoke(message);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (message.type === "shutdown") {
|
|
117
|
+
await this.handleShutdown(message.requestId, message.payload.reason);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (message.type === "fatal") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.failProcess("Plugin RPC message direction is invalid.");
|
|
124
|
+
}
|
|
125
|
+
async handleInitialize(message) {
|
|
126
|
+
if (this.initialized || this.shuttingDown) {
|
|
127
|
+
this.failProcess("Plugin host process was initialized more than once.");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const payload = message.payload;
|
|
131
|
+
this.initialized = true;
|
|
132
|
+
this.pluginId = payload.pluginId;
|
|
133
|
+
this.pluginDirectory = payload.pluginDirectory;
|
|
134
|
+
this.pluginDataDirectory = payload.pluginDataDirectory;
|
|
135
|
+
this.manifest = payload.manifest;
|
|
136
|
+
this.hostVersion = payload.hostVersion;
|
|
137
|
+
this.hostApiVersion = payload.hostApiVersion;
|
|
138
|
+
try {
|
|
139
|
+
if (!payload.manifest.mainEntry) {
|
|
140
|
+
throw new Error("Plugin manifest does not declare mainEntry.");
|
|
141
|
+
}
|
|
142
|
+
const mainEntryPath = path.resolve(payload.pluginDirectory, payload.manifest.mainEntry);
|
|
143
|
+
this.module = this.requireModule(mainEntryPath);
|
|
144
|
+
const activate = typeof this.module.activate === "function" ? this.module.activate : this.module.default?.activate;
|
|
145
|
+
if (typeof activate === "function") {
|
|
146
|
+
await activate({
|
|
147
|
+
pluginId: this.pluginId,
|
|
148
|
+
pluginDirectory: this.pluginDirectory,
|
|
149
|
+
manifest: this.manifest,
|
|
150
|
+
host: this.createHostApi()
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (this.exiting || this.shuttingDown) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this.ready = true;
|
|
157
|
+
this.port.postMessage({
|
|
158
|
+
protocolVersion: plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION,
|
|
159
|
+
type: "ready",
|
|
160
|
+
requestId: message.requestId,
|
|
161
|
+
payload: {
|
|
162
|
+
operations: Array.from(this.operations.keys()),
|
|
163
|
+
activatedAtUtc: this.now()
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
this.failProcess(error instanceof Error ? error.message : String(error));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async handleInvoke(message) {
|
|
172
|
+
if (!this.ready || this.shuttingDown) {
|
|
173
|
+
this.sendResult(message.requestId, createPluginRpcFailure(plugin_rpc_1.PluginRpcErrorCodes.NotReady, "Plugin host process is not ready."));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const handler = this.operations.get(message.payload.operation);
|
|
177
|
+
if (!handler) {
|
|
178
|
+
this.sendResult(message.requestId, createPluginRpcFailure("NotFound", "Plugin renderer operation was not registered.", {
|
|
179
|
+
pluginId: this.pluginId,
|
|
180
|
+
operation: message.payload.operation
|
|
181
|
+
}));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const result = await handler({
|
|
186
|
+
pluginId: this.pluginId,
|
|
187
|
+
surface: message.payload.surface,
|
|
188
|
+
contributionId: message.payload.contributionId,
|
|
189
|
+
operation: message.payload.operation,
|
|
190
|
+
input: message.payload.input
|
|
191
|
+
});
|
|
192
|
+
this.sendResult(message.requestId, normalizePluginResult(result));
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
const messageText = error instanceof Error ? error.message : String(error);
|
|
196
|
+
this.sendResult(message.requestId, createPluginRpcFailure("UnexpectedFailure", "Plugin renderer operation failed.", {
|
|
197
|
+
pluginId: this.pluginId,
|
|
198
|
+
operation: message.payload.operation,
|
|
199
|
+
message: messageText
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async handleTrackedInvoke(message) {
|
|
204
|
+
const operation = this.handleInvoke(message);
|
|
205
|
+
this.inFlightOperations.add(operation);
|
|
206
|
+
try {
|
|
207
|
+
await operation;
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
this.inFlightOperations.delete(operation);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async handleShutdown(requestId, reason) {
|
|
214
|
+
if (this.shuttingDown) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.shuttingDown = true;
|
|
218
|
+
try {
|
|
219
|
+
await Promise.allSettled(Array.from(this.inFlightOperations));
|
|
220
|
+
const deactivate = this.module && (typeof this.module.deactivate === "function" ? this.module.deactivate : this.module.default?.deactivate);
|
|
221
|
+
if (typeof deactivate === "function") {
|
|
222
|
+
await deactivate(reason);
|
|
223
|
+
}
|
|
224
|
+
this.sendResult(requestId, { ok: true, value: true });
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.sendResult(requestId, createPluginRpcFailure("UnexpectedFailure", "Plugin shutdown failed.", error instanceof Error ? error.message : String(error)));
|
|
228
|
+
}
|
|
229
|
+
this.dispose();
|
|
230
|
+
setImmediate(() => this.exit(0));
|
|
231
|
+
}
|
|
232
|
+
createHostApi() {
|
|
233
|
+
const manifest = this.manifest;
|
|
234
|
+
const unsupported = (permission) => {
|
|
235
|
+
const supportState = hostControlPermissions.has(permission)
|
|
236
|
+
? "hostControl"
|
|
237
|
+
: implementedPermissions.has(permission)
|
|
238
|
+
? "implemented"
|
|
239
|
+
: routeGuardPermissions.has(permission)
|
|
240
|
+
? "routeGuard"
|
|
241
|
+
: "reserved";
|
|
242
|
+
const target = {
|
|
243
|
+
permission,
|
|
244
|
+
supportState,
|
|
245
|
+
describe: () => this.requestHost("getCapabilityStatus", { permission }),
|
|
246
|
+
unsupported: (operation) => this.requestHost("unsupportedCapability", { permission, ...(typeof operation === "string" ? { operation } : {}) })
|
|
247
|
+
};
|
|
248
|
+
return new Proxy(target, {
|
|
249
|
+
get: (apiTarget, property) => {
|
|
250
|
+
if (property in apiTarget) {
|
|
251
|
+
return Reflect.get(apiTarget, property);
|
|
252
|
+
}
|
|
253
|
+
if (typeof property === "symbol" || property === "then") {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
return () => apiTarget.unsupported(property);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
this.electronFacadeClient?.dispose();
|
|
261
|
+
this.electronFacadeClient = (0, plugin_electron_facade_client_1.createPluginElectronFacadeClient)((request) => this.requestHost("electronFacade", request));
|
|
262
|
+
const electron = this.electronFacadeClient.electron;
|
|
263
|
+
return {
|
|
264
|
+
hostVersion: this.hostVersion,
|
|
265
|
+
hostApiVersion: this.hostApiVersion,
|
|
266
|
+
pluginId: this.pluginId,
|
|
267
|
+
pluginDataDirectory: this.pluginDataDirectory,
|
|
268
|
+
hasPermission: (permission) => manifest.permissions.includes(permission),
|
|
269
|
+
registerRendererMethod: async (name, handler) => {
|
|
270
|
+
if (!(0, plugin_rpc_1.isPluginRpcOperationName)(name) || typeof handler !== "function") {
|
|
271
|
+
return createPluginRpcFailure("InvalidRequest", "Plugin renderer operation registration is invalid.");
|
|
272
|
+
}
|
|
273
|
+
if (this.operations.has(name)) {
|
|
274
|
+
return createPluginRpcFailure("InvalidRequest", "Plugin renderer operation is already registered.");
|
|
275
|
+
}
|
|
276
|
+
this.operations.set(name, handler);
|
|
277
|
+
return { ok: true, value: true };
|
|
278
|
+
},
|
|
279
|
+
getCapabilityStatus: (permission) => this.requestHost("getCapabilityStatus", { permission: typeof permission === "string" ? permission : String(permission) }),
|
|
280
|
+
unsupportedCapability: (permission, operation) => this.requestHost("unsupportedCapability", { permission: typeof permission === "string" ? permission : String(permission), ...(typeof operation === "string" ? { operation } : {}) }),
|
|
281
|
+
log: (level, message, exception) => this.requestHost("log", {
|
|
282
|
+
level,
|
|
283
|
+
message,
|
|
284
|
+
...(exception ? { exception } : {})
|
|
285
|
+
}),
|
|
286
|
+
getSettings: () => this.requestHost("getSettings"),
|
|
287
|
+
updateSettings: (values) => this.requestHost("updateSettings", { values: (0, plugin_rpc_1.sanitizePluginRpcValue)(values) }),
|
|
288
|
+
electron,
|
|
289
|
+
filesystem: unsupported("filesystem"),
|
|
290
|
+
udp: unsupported("udp"),
|
|
291
|
+
serial: unsupported("serial"),
|
|
292
|
+
dialog: unsupported("dialog"),
|
|
293
|
+
externalProcess: unsupported("externalProcess")
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
requestHost(method, params) {
|
|
297
|
+
if (this.exiting) {
|
|
298
|
+
return Promise.resolve(createPluginRpcFailure(plugin_rpc_1.PluginRpcErrorCodes.ProcessExited, "Plugin host process is stopping."));
|
|
299
|
+
}
|
|
300
|
+
const requestId = (0, plugin_rpc_1.createPluginRpcRequestId)(this.pluginId + "-host", ++this.requestSequence);
|
|
301
|
+
return new Promise((resolve, reject) => {
|
|
302
|
+
this.pendingHostRequests.set(requestId, { resolve, reject });
|
|
303
|
+
try {
|
|
304
|
+
this.port.postMessage({
|
|
305
|
+
protocolVersion: plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION,
|
|
306
|
+
type: "hostRequest",
|
|
307
|
+
requestId,
|
|
308
|
+
payload: { method, ...(params ? { params: (0, plugin_rpc_1.sanitizePluginRpcValue)(params) } : {}) }
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
this.pendingHostRequests.delete(requestId);
|
|
313
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
handleHostResult(requestId, result) {
|
|
318
|
+
const pending = this.pendingHostRequests.get(requestId);
|
|
319
|
+
if (!pending) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
this.pendingHostRequests.delete(requestId);
|
|
323
|
+
pending.resolve(result);
|
|
324
|
+
}
|
|
325
|
+
async handleElectronCallback(requestId, callbackId, args) {
|
|
326
|
+
const result = this.electronFacadeClient
|
|
327
|
+
? await this.electronFacadeClient.invokeCallback(callbackId, args)
|
|
328
|
+
: createPluginRpcFailure(plugin_rpc_1.PluginRpcErrorCodes.NotReady, "Electron facade client is not ready.");
|
|
329
|
+
this.port.postMessage({
|
|
330
|
+
protocolVersion: plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION,
|
|
331
|
+
type: "electronCallbackResult",
|
|
332
|
+
requestId,
|
|
333
|
+
result
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
sendResult(requestId, result) {
|
|
337
|
+
this.port.postMessage({
|
|
338
|
+
protocolVersion: plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION,
|
|
339
|
+
type: "result",
|
|
340
|
+
requestId,
|
|
341
|
+
result: normalizePluginResult(result)
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
sendFatal(message) {
|
|
345
|
+
try {
|
|
346
|
+
this.port.postMessage({
|
|
347
|
+
protocolVersion: plugin_rpc_1.PLUGIN_RPC_PROTOCOL_VERSION,
|
|
348
|
+
type: "fatal",
|
|
349
|
+
payload: { message: message || "Plugin host process failed." }
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
// The parent may already have closed the transport.
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
failProcess(message) {
|
|
357
|
+
if (this.exiting) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
this.exiting = true;
|
|
361
|
+
this.sendFatal(message);
|
|
362
|
+
setImmediate(() => this.exit(1));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function readMessageData(event) {
|
|
366
|
+
if (isRecordWithData(event)) {
|
|
367
|
+
return event.data;
|
|
368
|
+
}
|
|
369
|
+
return event;
|
|
370
|
+
}
|
|
371
|
+
function isRecordWithData(value) {
|
|
372
|
+
return typeof value === "object" && value !== null && "data" in value;
|
|
373
|
+
}
|
|
374
|
+
function loadPluginMainModule(mainEntryPath) {
|
|
375
|
+
const moduleApi = module.require("module");
|
|
376
|
+
const pluginRequire = moduleApi.createRequire(mainEntryPath);
|
|
377
|
+
return pluginRequire(mainEntryPath);
|
|
378
|
+
}
|
|
379
|
+
function normalizePluginResult(value) {
|
|
380
|
+
if (isNexusResult(value)) {
|
|
381
|
+
if (!value.ok) {
|
|
382
|
+
return {
|
|
383
|
+
ok: false,
|
|
384
|
+
error: {
|
|
385
|
+
code: value.error.code,
|
|
386
|
+
message: value.error.message,
|
|
387
|
+
...(value.error.details === undefined ? {} : { details: (0, plugin_rpc_1.sanitizePluginRpcValue)(value.error.details) })
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
return { ok: true, value: (0, plugin_rpc_1.sanitizePluginRpcValue)(value.value) };
|
|
392
|
+
}
|
|
393
|
+
return { ok: true, value: (0, plugin_rpc_1.sanitizePluginRpcValue)(value) };
|
|
394
|
+
}
|
|
395
|
+
function isNexusResult(value) {
|
|
396
|
+
return isRecord(value)
|
|
397
|
+
&& typeof value.ok === "boolean"
|
|
398
|
+
&& (value.ok
|
|
399
|
+
? "value" in value
|
|
400
|
+
: isRecord(value.error) && typeof value.error.code === "string" && typeof value.error.message === "string");
|
|
401
|
+
}
|
|
402
|
+
function createPluginRpcFailure(code, message, details) {
|
|
403
|
+
return {
|
|
404
|
+
ok: false,
|
|
405
|
+
error: {
|
|
406
|
+
code,
|
|
407
|
+
message,
|
|
408
|
+
...(details === undefined ? {} : { details: (0, plugin_rpc_1.sanitizePluginRpcValue)(details) })
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function isRecord(value) {
|
|
413
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
414
|
+
}
|
|
415
|
+
if (process.type === "utility" && process.parentPort) {
|
|
416
|
+
runPluginHostBootstrap(process.parentPort, { installProcessHandlers: true });
|
|
417
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPluginElectronFacade = exports.createPluginElectronFacadeClient = void 0;
|
|
4
|
+
const plugin_electron_facade_1 = require("./plugin-electron-facade");
|
|
5
|
+
function createPluginElectronFacadeClient(request) {
|
|
6
|
+
const remoteHandles = new WeakMap();
|
|
7
|
+
const callbacks = new Map();
|
|
8
|
+
let callbackSequence = 0;
|
|
9
|
+
let disposed = false;
|
|
10
|
+
const registerCallback = (callback, once = false) => {
|
|
11
|
+
if (disposed) {
|
|
12
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade client is disposed.");
|
|
13
|
+
}
|
|
14
|
+
const callbackId = "electron-callback:" + String(++callbackSequence);
|
|
15
|
+
callbacks.set(callbackId, { callback, once });
|
|
16
|
+
return { $nexusElectron: "callback", callbackId };
|
|
17
|
+
};
|
|
18
|
+
const encodeArgument = (value) => (0, plugin_electron_facade_1.encodeElectronFacadeValue)(value, {
|
|
19
|
+
encodeFunction: (functionValue) => {
|
|
20
|
+
const metadata = remoteHandles.get(functionValue);
|
|
21
|
+
return metadata ? handleTag(metadata) : registerCallback(functionValue);
|
|
22
|
+
},
|
|
23
|
+
encodeObject: (objectValue) => {
|
|
24
|
+
const metadata = remoteHandles.get(objectValue);
|
|
25
|
+
if (metadata) {
|
|
26
|
+
return handleTag(metadata);
|
|
27
|
+
}
|
|
28
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Only Electron remote handles can cross the facade boundary.");
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const createTarget = (target, metadata) => {
|
|
32
|
+
const callable = () => undefined;
|
|
33
|
+
const proxy = new Proxy(callable, {
|
|
34
|
+
get: (_proxyTarget, property) => {
|
|
35
|
+
if (property === "then") {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
if (property === "$typeName") {
|
|
39
|
+
return metadata?.typeName;
|
|
40
|
+
}
|
|
41
|
+
if (property === "$construct") {
|
|
42
|
+
return (...args) => invoke(target, "construct", undefined, args);
|
|
43
|
+
}
|
|
44
|
+
if (property === "$get") {
|
|
45
|
+
return (member) => invoke(target, "get", requireMember(member));
|
|
46
|
+
}
|
|
47
|
+
if (property === "$set") {
|
|
48
|
+
return (member, value) => invoke(target, "set", requireMember(member), [value]);
|
|
49
|
+
}
|
|
50
|
+
if (property === "$on" || property === "$once") {
|
|
51
|
+
return (event, listener) => subscribe(target, property === "$once" ? "once" : "on", event, listener);
|
|
52
|
+
}
|
|
53
|
+
if (property === "$release") {
|
|
54
|
+
return async () => {
|
|
55
|
+
if (!target.handleId) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await invoke(target, "release");
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
if (metadata?.callbackId) {
|
|
63
|
+
callbacks.delete(metadata.callbackId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (typeof property === "symbol") {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return (...args) => invoke(target, "call", property, args);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (metadata) {
|
|
75
|
+
remoteHandles.set(proxy, metadata);
|
|
76
|
+
}
|
|
77
|
+
return proxy;
|
|
78
|
+
};
|
|
79
|
+
const decodeValue = (value) => (0, plugin_electron_facade_1.decodeElectronFacadeValue)(value, {
|
|
80
|
+
decodeHandle: (handleId, typeName, callbackId) => createTarget({ handleId }, { handleId, typeName, callbackId })
|
|
81
|
+
});
|
|
82
|
+
const invoke = async (target, operation, member, args) => {
|
|
83
|
+
if (disposed) {
|
|
84
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade client is disposed.");
|
|
85
|
+
}
|
|
86
|
+
const result = await request({
|
|
87
|
+
operation,
|
|
88
|
+
...target,
|
|
89
|
+
...(member ? { member } : {}),
|
|
90
|
+
...(args ? { args: args.map(encodeArgument) } : {})
|
|
91
|
+
});
|
|
92
|
+
return (0, plugin_electron_facade_1.unwrapElectronFacadeResult)(result, {
|
|
93
|
+
decodeHandle: (handleId, typeName, callbackId) => createTarget({ handleId }, { handleId, typeName, callbackId })
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const subscribe = async (target, operation, event, listener) => {
|
|
97
|
+
const member = requireMember(event);
|
|
98
|
+
if (typeof listener !== "function") {
|
|
99
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade event listener must be a function.");
|
|
100
|
+
}
|
|
101
|
+
const callbackTag = registerCallback(listener, operation === "once");
|
|
102
|
+
const callbackId = callbackTag.callbackId;
|
|
103
|
+
try {
|
|
104
|
+
return await invokeEncoded(target, operation, member, [callbackTag]);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
callbacks.delete(callbackId);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const invokeEncoded = async (target, operation, member, args) => {
|
|
112
|
+
if (disposed) {
|
|
113
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade client is disposed.");
|
|
114
|
+
}
|
|
115
|
+
const result = await request({ operation, ...target, member, args });
|
|
116
|
+
return (0, plugin_electron_facade_1.unwrapElectronFacadeResult)(result, {
|
|
117
|
+
decodeHandle: (handleId, typeName, callbackId) => createTarget({ handleId }, { handleId, typeName, callbackId })
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
const invokeRegisteredCallback = async (callbackId, args) => {
|
|
121
|
+
const record = callbacks.get(callbackId);
|
|
122
|
+
if (!record || disposed) {
|
|
123
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade callback is unavailable or released.");
|
|
124
|
+
}
|
|
125
|
+
if (record.once) {
|
|
126
|
+
callbacks.delete(callbackId);
|
|
127
|
+
}
|
|
128
|
+
return record.callback(...args.map(decodeValue));
|
|
129
|
+
};
|
|
130
|
+
const electron = new Proxy({}, {
|
|
131
|
+
get: (_target, property) => {
|
|
132
|
+
if (property === "then" || typeof property === "symbol") {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
return createTarget({ module: property });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
electron,
|
|
140
|
+
async invokeCallback(callbackId, args) {
|
|
141
|
+
try {
|
|
142
|
+
return { ok: true, value: encodeArgument(await invokeRegisteredCallback(callbackId, args)) };
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
error: {
|
|
148
|
+
code: error instanceof plugin_electron_facade_1.ElectronFacadeCodecError ? error.code : plugin_electron_facade_1.ElectronFacadeErrorCodes.InvocationFailed,
|
|
149
|
+
message: error instanceof Error ? error.message : String(error)
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
emitEvent(callbackId, args) {
|
|
155
|
+
void Promise.resolve(invokeRegisteredCallback(callbackId, args)).catch(() => undefined);
|
|
156
|
+
},
|
|
157
|
+
dispose() {
|
|
158
|
+
disposed = true;
|
|
159
|
+
callbacks.clear();
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
exports.createPluginElectronFacadeClient = createPluginElectronFacadeClient;
|
|
164
|
+
function createPluginElectronFacade(request) {
|
|
165
|
+
return createPluginElectronFacadeClient(request).electron;
|
|
166
|
+
}
|
|
167
|
+
exports.createPluginElectronFacade = createPluginElectronFacade;
|
|
168
|
+
function handleTag(metadata) {
|
|
169
|
+
return {
|
|
170
|
+
$nexusElectron: "handle",
|
|
171
|
+
handleId: metadata.handleId,
|
|
172
|
+
typeName: metadata.typeName,
|
|
173
|
+
...(metadata.callbackId ? { callbackId: metadata.callbackId } : {})
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function requireMember(value) {
|
|
177
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
178
|
+
throw new plugin_electron_facade_1.ElectronFacadeCodecError("Electron facade member name is required.");
|
|
179
|
+
}
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getElectronFacadeSpecialMemberDescriptor = exports.getElectronFacadeExportDescriptor = exports.electronFacadeSpecialMemberDescriptors = exports.electronFacadeExportDescriptors = void 0;
|
|
4
|
+
// Runtime values exported by Electron 22.3.27's Common/Main/CrossProcessExports namespaces.
|
|
5
|
+
exports.electronFacadeExportDescriptors = [
|
|
6
|
+
{ name: "clipboard", process: "common", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
7
|
+
{ name: "crashReporter", process: "common", kind: "module", defaultAccess: "hostControl", cleanup: "irreversible" },
|
|
8
|
+
{ name: "nativeImage", process: "common", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
9
|
+
{ name: "shell", process: "common", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
10
|
+
{ name: "app", process: "main", kind: "module", defaultAccess: "basic", cleanup: "irreversible" },
|
|
11
|
+
{ name: "autoUpdater", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "irreversible" },
|
|
12
|
+
{ name: "BrowserView", process: "main", kind: "constructor", defaultAccess: "owned", cleanup: "owned" },
|
|
13
|
+
{ name: "BrowserWindow", process: "main", kind: "constructor", defaultAccess: "owned", cleanup: "owned" },
|
|
14
|
+
{ name: "contentTracing", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "bestEffort" },
|
|
15
|
+
{ name: "desktopCapturer", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "none" },
|
|
16
|
+
{ name: "dialog", process: "main", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
17
|
+
{ name: "globalShortcut", process: "main", kind: "module", defaultAccess: "owned", cleanup: "tracked" },
|
|
18
|
+
{ name: "inAppPurchase", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "irreversible" },
|
|
19
|
+
{ name: "ipcMain", process: "main", kind: "module", defaultAccess: "owned", cleanup: "tracked" },
|
|
20
|
+
{ name: "Menu", process: "main", kind: "constructor", defaultAccess: "owned", cleanup: "bestEffort" },
|
|
21
|
+
{ name: "MenuItem", process: "main", kind: "constructor", defaultAccess: "hostControl", cleanup: "owned" },
|
|
22
|
+
{ name: "MessageChannelMain", process: "main", kind: "constructor", defaultAccess: "hostControl", cleanup: "owned" },
|
|
23
|
+
{ name: "nativeTheme", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "bestEffort" },
|
|
24
|
+
{ name: "net", process: "main", kind: "module", defaultAccess: "owned", cleanup: "tracked" },
|
|
25
|
+
{ name: "netLog", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "bestEffort" },
|
|
26
|
+
{ name: "Notification", process: "main", kind: "constructor", defaultAccess: "owned", cleanup: "owned" },
|
|
27
|
+
{ name: "powerMonitor", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "tracked" },
|
|
28
|
+
{ name: "powerSaveBlocker", process: "main", kind: "module", defaultAccess: "owned", cleanup: "tracked" },
|
|
29
|
+
{ name: "protocol", process: "main", kind: "module", defaultAccess: "owned", cleanup: "tracked" },
|
|
30
|
+
{ name: "pushNotifications", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "tracked" },
|
|
31
|
+
{ name: "safeStorage", process: "main", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
32
|
+
{ name: "screen", process: "main", kind: "module", defaultAccess: "basic", cleanup: "none" },
|
|
33
|
+
{ name: "session", process: "main", kind: "module", defaultAccess: "owned", cleanup: "owned" },
|
|
34
|
+
{ name: "ShareMenu", process: "main", kind: "constructor", defaultAccess: "hostControl", cleanup: "owned" },
|
|
35
|
+
{ name: "systemPreferences", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "bestEffort" },
|
|
36
|
+
{ name: "TouchBar", process: "main", kind: "constructor", defaultAccess: "hostControl", cleanup: "owned" },
|
|
37
|
+
{ name: "Tray", process: "main", kind: "constructor", defaultAccess: "owned", cleanup: "owned" },
|
|
38
|
+
{ name: "utilityProcess", process: "main", kind: "module", defaultAccess: "owned", cleanup: "owned" },
|
|
39
|
+
{ name: "webContents", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "tracked" },
|
|
40
|
+
{ name: "webFrameMain", process: "main", kind: "module", defaultAccess: "hostControl", cleanup: "none" },
|
|
41
|
+
{ name: "contextBridge", process: "renderer", kind: "module", defaultAccess: "unavailable", cleanup: "none" },
|
|
42
|
+
{ name: "ipcRenderer", process: "renderer", kind: "module", defaultAccess: "unavailable", cleanup: "none" },
|
|
43
|
+
{ name: "webFrame", process: "renderer", kind: "module", defaultAccess: "unavailable", cleanup: "none" }
|
|
44
|
+
];
|
|
45
|
+
exports.electronFacadeSpecialMemberDescriptors = [
|
|
46
|
+
{ owner: "app", member: "disableDomainBlockingFor3DAPIs", behavior: "lifecycle", reason: "must run before app ready" },
|
|
47
|
+
{ owner: "app", member: "disableHardwareAcceleration", behavior: "lifecycle", reason: "must run before app ready" },
|
|
48
|
+
{ owner: "app", member: "enableSandbox", behavior: "lifecycle", reason: "must run before app ready" },
|
|
49
|
+
{ owner: "protocol", member: "registerSchemesAsPrivileged", behavior: "lifecycle", reason: "must run before app ready" },
|
|
50
|
+
{ owner: "WebContents", member: "setWindowOpenHandler", behavior: "synchronousCallback", reason: "Electron requires an immediate decision" },
|
|
51
|
+
{ owner: "Session", member: "setPermissionCheckHandler", behavior: "synchronousCallback", reason: "Electron requires an immediate decision" },
|
|
52
|
+
{ owner: "Session", member: "setDevicePermissionHandler", behavior: "synchronousCallback", reason: "Electron requires an immediate decision" },
|
|
53
|
+
{ owner: "Session", member: "setBluetoothPairingHandler", behavior: "synchronousCallback", reason: "Electron native continuation callbacks cannot cross the asynchronous RPC boundary" },
|
|
54
|
+
{ owner: "Session", member: "setCertificateVerifyProc", behavior: "synchronousCallback", reason: "Electron native continuation callbacks cannot cross the asynchronous RPC boundary" },
|
|
55
|
+
{ owner: "Session", member: "setDisplayMediaRequestHandler", behavior: "synchronousCallback", reason: "Electron native continuation callbacks cannot cross the asynchronous RPC boundary" },
|
|
56
|
+
{ owner: "Session", member: "setPermissionRequestHandler", behavior: "synchronousCallback", reason: "Electron native continuation callbacks cannot cross the asynchronous RPC boundary" },
|
|
57
|
+
{ owner: "WebRequest", member: "onBeforeRequest", behavior: "synchronousCallback", reason: "Electron callback continuation is not RPC-safe" },
|
|
58
|
+
{ owner: "WebRequest", member: "onBeforeSendHeaders", behavior: "synchronousCallback", reason: "Electron callback continuation is not RPC-safe" },
|
|
59
|
+
{ owner: "WebRequest", member: "onHeadersReceived", behavior: "synchronousCallback", reason: "Electron callback continuation is not RPC-safe" }
|
|
60
|
+
];
|
|
61
|
+
const exportDescriptorsByName = new Map(exports.electronFacadeExportDescriptors.map((descriptor) => [descriptor.name, descriptor]));
|
|
62
|
+
const specialMembersByKey = new Map(exports.electronFacadeSpecialMemberDescriptors.map((descriptor) => [descriptor.owner + "." + descriptor.member, descriptor]));
|
|
63
|
+
function getElectronFacadeExportDescriptor(name) {
|
|
64
|
+
return exportDescriptorsByName.get(name);
|
|
65
|
+
}
|
|
66
|
+
exports.getElectronFacadeExportDescriptor = getElectronFacadeExportDescriptor;
|
|
67
|
+
function getElectronFacadeSpecialMemberDescriptor(owner, member) {
|
|
68
|
+
return specialMembersByKey.get(owner + "." + member);
|
|
69
|
+
}
|
|
70
|
+
exports.getElectronFacadeSpecialMemberDescriptor = getElectronFacadeSpecialMemberDescriptor;
|