@novasamatech/host-container 0.5.3-0 → 0.5.4-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/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/createContainer.js +74 -21
- package/dist/createWebviewProvider.d.ts +8 -0
- package/dist/createWebviewProvider.js +99 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +8 -5
- package/package.json +6 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WEBVIEW_HOST_PORT_NAME = "__HOST_API_PORT__";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WEBVIEW_HOST_PORT_NAME = '__HOST_API_PORT__';
|
package/dist/createContainer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatMessagePostingErr, ChatRoomRegistrationErr, CreateProofErr, CreateTransactionErr, GenericError, RequestCredentialsErr, SigningErr, StatementProofErr, StorageErr, assertEnumVariant, createTransport, enumValue, isEnumVariant, resultErr, resultOk, } from '@novasamatech/host-api';
|
|
2
2
|
import { err, errAsync, ok, okAsync } from 'neverthrow';
|
|
3
3
|
const UNSUPPORTED_MESSAGE_FORMAT_ERROR = 'Unsupported message format';
|
|
4
4
|
function guardVersion(value, tag, error) {
|
|
@@ -18,6 +18,7 @@ export function createContainer(provider) {
|
|
|
18
18
|
}
|
|
19
19
|
return {
|
|
20
20
|
handleFeature(handler) {
|
|
21
|
+
init();
|
|
21
22
|
return transport.handleRequest('feature', async (message) => {
|
|
22
23
|
const version = 'v1';
|
|
23
24
|
const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -28,19 +29,9 @@ export function createContainer(provider) {
|
|
|
28
29
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
29
30
|
});
|
|
30
31
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const error = new PermissionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
35
|
-
return guardVersion(message, version, error)
|
|
36
|
-
.asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
|
|
37
|
-
.andThen(r => r.map(r => enumValue(version, resultOk(r))))
|
|
38
|
-
.orElse(r => ok(enumValue(version, resultErr(r))))
|
|
39
|
-
.unwrapOr(enumValue(version, resultErr(error)));
|
|
40
|
-
});
|
|
41
|
-
},
|
|
42
|
-
handleStorageRead(handler) {
|
|
43
|
-
return transport.handleRequest('storage_read', async (message) => {
|
|
32
|
+
handleLocalStorageRead(handler) {
|
|
33
|
+
init();
|
|
34
|
+
return transport.handleRequest('local_storage_read', async (message) => {
|
|
44
35
|
const version = 'v1';
|
|
45
36
|
const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
46
37
|
return guardVersion(message, version, error)
|
|
@@ -50,8 +41,9 @@ export function createContainer(provider) {
|
|
|
50
41
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
51
42
|
});
|
|
52
43
|
},
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
handleLocalStorageWrite(handler) {
|
|
45
|
+
init();
|
|
46
|
+
return transport.handleRequest('local_storage_write', async (message) => {
|
|
55
47
|
const version = 'v1';
|
|
56
48
|
const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
57
49
|
return guardVersion(message, version, error)
|
|
@@ -61,8 +53,9 @@ export function createContainer(provider) {
|
|
|
61
53
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
62
54
|
});
|
|
63
55
|
},
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
handleLocalStorageClear(handler) {
|
|
57
|
+
init();
|
|
58
|
+
return transport.handleRequest('local_storage_clear', async (params) => {
|
|
66
59
|
const version = 'v1';
|
|
67
60
|
const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
68
61
|
return guardVersion(params, version, error)
|
|
@@ -73,6 +66,7 @@ export function createContainer(provider) {
|
|
|
73
66
|
});
|
|
74
67
|
},
|
|
75
68
|
handleAccountGet(handler) {
|
|
69
|
+
init();
|
|
76
70
|
return transport.handleRequest('account_get', async (params) => {
|
|
77
71
|
const version = 'v1';
|
|
78
72
|
const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -84,6 +78,7 @@ export function createContainer(provider) {
|
|
|
84
78
|
});
|
|
85
79
|
},
|
|
86
80
|
handleAccountGetAlias(handler) {
|
|
81
|
+
init();
|
|
87
82
|
return transport.handleRequest('account_get_alias', async (params) => {
|
|
88
83
|
const version = 'v1';
|
|
89
84
|
const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -95,6 +90,7 @@ export function createContainer(provider) {
|
|
|
95
90
|
});
|
|
96
91
|
},
|
|
97
92
|
handleAccountCreateProof(handler) {
|
|
93
|
+
init();
|
|
98
94
|
return transport.handleRequest('account_create_proof', async (params) => {
|
|
99
95
|
const version = 'v1';
|
|
100
96
|
const error = new CreateProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -106,6 +102,7 @@ export function createContainer(provider) {
|
|
|
106
102
|
});
|
|
107
103
|
},
|
|
108
104
|
handleGetNonProductAccounts(handler) {
|
|
105
|
+
init();
|
|
109
106
|
return transport.handleRequest('get_non_product_accounts', async (params) => {
|
|
110
107
|
const version = 'v1';
|
|
111
108
|
const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -117,6 +114,7 @@ export function createContainer(provider) {
|
|
|
117
114
|
});
|
|
118
115
|
},
|
|
119
116
|
handleCreateTransaction(handler) {
|
|
117
|
+
init();
|
|
120
118
|
return transport.handleRequest('create_transaction', async (params) => {
|
|
121
119
|
const version = 'v1';
|
|
122
120
|
const error = new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -128,6 +126,7 @@ export function createContainer(provider) {
|
|
|
128
126
|
});
|
|
129
127
|
},
|
|
130
128
|
handleCreateTransactionWithNonProductAccount(handler) {
|
|
129
|
+
init();
|
|
131
130
|
return transport.handleRequest('create_transaction_with_non_product_account', async (params) => {
|
|
132
131
|
const version = 'v1';
|
|
133
132
|
const error = new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -139,6 +138,7 @@ export function createContainer(provider) {
|
|
|
139
138
|
});
|
|
140
139
|
},
|
|
141
140
|
handleSignRaw(handler) {
|
|
141
|
+
init();
|
|
142
142
|
return transport.handleRequest('sign_raw', async (params) => {
|
|
143
143
|
const version = 'v1';
|
|
144
144
|
const error = new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -150,6 +150,7 @@ export function createContainer(provider) {
|
|
|
150
150
|
});
|
|
151
151
|
},
|
|
152
152
|
handleSignPayload(handler) {
|
|
153
|
+
init();
|
|
153
154
|
return transport.handleRequest('sign_payload', async (params) => {
|
|
154
155
|
const version = 'v1';
|
|
155
156
|
const error = new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -160,10 +161,11 @@ export function createContainer(provider) {
|
|
|
160
161
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
161
162
|
});
|
|
162
163
|
},
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
handleChatCreateRoom(handler) {
|
|
165
|
+
init();
|
|
166
|
+
return transport.handleRequest('chat_create_room', async (params) => {
|
|
165
167
|
const version = 'v1';
|
|
166
|
-
const error = new
|
|
168
|
+
const error = new ChatRoomRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
167
169
|
return guardVersion(params, version, error)
|
|
168
170
|
.asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
|
|
169
171
|
.andThen(r => r.map(r => enumValue(version, resultOk(r))))
|
|
@@ -171,7 +173,20 @@ export function createContainer(provider) {
|
|
|
171
173
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
172
174
|
});
|
|
173
175
|
},
|
|
176
|
+
handleChatListSubscribe(handler) {
|
|
177
|
+
init();
|
|
178
|
+
return transport.handleSubscription('chat_list_subscribe', (params, send, interrupt) => {
|
|
179
|
+
const version = 'v1';
|
|
180
|
+
return guardVersion(params, version, null)
|
|
181
|
+
.map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
|
|
182
|
+
.orTee(interrupt)
|
|
183
|
+
.unwrapOr(() => {
|
|
184
|
+
/* empty */
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
},
|
|
174
188
|
handleChatPostMessage(handler) {
|
|
189
|
+
init();
|
|
175
190
|
return transport.handleRequest('chat_post_message', async (params) => {
|
|
176
191
|
const version = 'v1';
|
|
177
192
|
const error = new ChatMessagePostingErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -183,6 +198,7 @@ export function createContainer(provider) {
|
|
|
183
198
|
});
|
|
184
199
|
},
|
|
185
200
|
handleChatActionSubscribe(handler) {
|
|
201
|
+
init();
|
|
186
202
|
return transport.handleSubscription('chat_action_subscribe', (params, send, interrupt) => {
|
|
187
203
|
const version = 'v1';
|
|
188
204
|
return guardVersion(params, version, null)
|
|
@@ -193,7 +209,32 @@ export function createContainer(provider) {
|
|
|
193
209
|
});
|
|
194
210
|
});
|
|
195
211
|
},
|
|
212
|
+
handleStatementStoreQuery(handler) {
|
|
213
|
+
init();
|
|
214
|
+
return transport.handleRequest('statement_store_query', async (params) => {
|
|
215
|
+
const version = 'v1';
|
|
216
|
+
const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
217
|
+
return guardVersion(params, version, error)
|
|
218
|
+
.asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
|
|
219
|
+
.andThen(r => r.map(r => enumValue(version, resultOk(r))))
|
|
220
|
+
.orElse(r => ok(enumValue(version, resultErr(r))))
|
|
221
|
+
.unwrapOr(enumValue(version, resultErr(error)));
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
handleStatementStoreSubscribe(handler) {
|
|
225
|
+
init();
|
|
226
|
+
return transport.handleSubscription('statement_store_subscribe', (params, send, interrupt) => {
|
|
227
|
+
const version = 'v1';
|
|
228
|
+
return guardVersion(params, version, null)
|
|
229
|
+
.map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
|
|
230
|
+
.orTee(interrupt)
|
|
231
|
+
.unwrapOr(() => {
|
|
232
|
+
/* empty */
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
},
|
|
196
236
|
handleStatementStoreCreateProof(handler) {
|
|
237
|
+
init();
|
|
197
238
|
return transport.handleRequest('statement_store_create_proof', async (params) => {
|
|
198
239
|
const version = 'v1';
|
|
199
240
|
const error = new StatementProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
@@ -204,6 +245,18 @@ export function createContainer(provider) {
|
|
|
204
245
|
.unwrapOr(enumValue(version, resultErr(error)));
|
|
205
246
|
});
|
|
206
247
|
},
|
|
248
|
+
handleStatementStoreSubmit(handler) {
|
|
249
|
+
init();
|
|
250
|
+
return transport.handleRequest('statement_store_submit', async (params) => {
|
|
251
|
+
const version = 'v1';
|
|
252
|
+
const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
|
|
253
|
+
return guardVersion(params, version, error)
|
|
254
|
+
.asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
|
|
255
|
+
.andThen(r => r.map(r => enumValue(version, resultOk(r))))
|
|
256
|
+
.orElse(r => ok(enumValue(version, resultErr(r))))
|
|
257
|
+
.unwrapOr(enumValue(version, resultErr(error)));
|
|
258
|
+
});
|
|
259
|
+
},
|
|
207
260
|
handleJsonRpcMessageSubscribe(genesisHash, provider) {
|
|
208
261
|
init();
|
|
209
262
|
return transport.handleSubscription('jsonrpc_message_subscribe', (params, send) => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Logger, Provider } from '@novasamatech/host-api';
|
|
2
|
+
import type { WebviewTag } from 'electron';
|
|
3
|
+
type Params = {
|
|
4
|
+
webview: WebviewTag;
|
|
5
|
+
logger?: Logger;
|
|
6
|
+
};
|
|
7
|
+
export declare function createWebviewProvider({ webview, logger }: Params): Provider;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createDefaultLogger } from '@novasamatech/host-api';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import { WEBVIEW_HOST_PORT_NAME } from './constants.js';
|
|
4
|
+
function hasWindow() {
|
|
5
|
+
try {
|
|
6
|
+
return typeof window !== 'undefined';
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function isValidMessage(event, sourceEnv, currentEnv) {
|
|
13
|
+
return (event.source !== currentEnv &&
|
|
14
|
+
event.source === sourceEnv &&
|
|
15
|
+
event.data &&
|
|
16
|
+
event.data.constructor.name === 'Uint8Array');
|
|
17
|
+
}
|
|
18
|
+
export function createWebviewProvider({ webview, logger }) {
|
|
19
|
+
let disposed = false;
|
|
20
|
+
let subscribed = false;
|
|
21
|
+
let port = null;
|
|
22
|
+
const subscribers = new Set();
|
|
23
|
+
const webviewPromise = new Promise((resolve, reject) => {
|
|
24
|
+
webview.addEventListener('did-fail-load', e => {
|
|
25
|
+
reject(new Error(e.errorDescription));
|
|
26
|
+
});
|
|
27
|
+
webview.addEventListener('dom-ready', async () => {
|
|
28
|
+
const { port1, port2 } = new MessageChannel();
|
|
29
|
+
const portInitMessage = `PORT_INIT_${nanoid(12)}`;
|
|
30
|
+
port = port1;
|
|
31
|
+
await webview
|
|
32
|
+
.executeJavaScript(`
|
|
33
|
+
window.addEventListener('message', e => {
|
|
34
|
+
if (e.data === '${portInitMessage}') {
|
|
35
|
+
const port = e.ports[0];
|
|
36
|
+
if (port) {
|
|
37
|
+
window['${WEBVIEW_HOST_PORT_NAME}'] = port;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
`)
|
|
42
|
+
.catch(reject);
|
|
43
|
+
// @ts-expect-error contentWindow is undefined somehow
|
|
44
|
+
webview.contentWindow.postMessage(portInitMessage, '*', [port2]);
|
|
45
|
+
resolve(port);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
function waitForWebview(callback) {
|
|
49
|
+
if (port) {
|
|
50
|
+
return callback(port);
|
|
51
|
+
}
|
|
52
|
+
webviewPromise.then(callback);
|
|
53
|
+
}
|
|
54
|
+
const messageHandler = (event) => {
|
|
55
|
+
if (disposed)
|
|
56
|
+
return;
|
|
57
|
+
waitForWebview(port => {
|
|
58
|
+
if (disposed)
|
|
59
|
+
return;
|
|
60
|
+
if (!isValidMessage(event, port, window))
|
|
61
|
+
return;
|
|
62
|
+
for (const subscriber of subscribers) {
|
|
63
|
+
subscriber(event.data);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
logger: logger ?? createDefaultLogger(),
|
|
69
|
+
isCorrectEnvironment() {
|
|
70
|
+
return hasWindow();
|
|
71
|
+
},
|
|
72
|
+
postMessage(message) {
|
|
73
|
+
if (disposed)
|
|
74
|
+
return;
|
|
75
|
+
waitForWebview(port => {
|
|
76
|
+
if (disposed)
|
|
77
|
+
return;
|
|
78
|
+
port.postMessage(message, [message.buffer]);
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
subscribe(callback) {
|
|
82
|
+
if (!subscribed && port) {
|
|
83
|
+
subscribed = true;
|
|
84
|
+
port.addEventListener('message', messageHandler);
|
|
85
|
+
}
|
|
86
|
+
subscribers.add(callback);
|
|
87
|
+
return () => {
|
|
88
|
+
subscribers.delete(callback);
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
dispose() {
|
|
92
|
+
disposed = true;
|
|
93
|
+
subscribers.clear();
|
|
94
|
+
if (port) {
|
|
95
|
+
port.removeEventListener('message', messageHandler);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -51,10 +51,9 @@ type InferSubscribeHandler<V extends string, T extends VersionedProtocolSubscrip
|
|
|
51
51
|
type InferHandler<V extends string, T extends VersionedProtocolRequest | VersionedProtocolSubscription> = T extends VersionedProtocolRequest ? InferRequestHandler<V, T> : T extends VersionedProtocolSubscription ? InferSubscribeHandler<V, T> : never;
|
|
52
52
|
export type Container = {
|
|
53
53
|
handleFeature: InferHandler<'v1', HostApiProtocol['feature']>;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
handleStorageClear: InferHandler<'v1', HostApiProtocol['storage_clear']>;
|
|
54
|
+
handleLocalStorageRead: InferHandler<'v1', HostApiProtocol['local_storage_read']>;
|
|
55
|
+
handleLocalStorageWrite: InferHandler<'v1', HostApiProtocol['local_storage_write']>;
|
|
56
|
+
handleLocalStorageClear: InferHandler<'v1', HostApiProtocol['local_storage_clear']>;
|
|
58
57
|
handleAccountGet: InferHandler<'v1', HostApiProtocol['account_get']>;
|
|
59
58
|
handleAccountGetAlias: InferHandler<'v1', HostApiProtocol['account_get_alias']>;
|
|
60
59
|
handleAccountCreateProof: InferHandler<'v1', HostApiProtocol['account_create_proof']>;
|
|
@@ -63,10 +62,14 @@ export type Container = {
|
|
|
63
62
|
handleCreateTransactionWithNonProductAccount: InferHandler<'v1', HostApiProtocol['create_transaction_with_non_product_account']>;
|
|
64
63
|
handleSignRaw: InferHandler<'v1', HostApiProtocol['sign_raw']>;
|
|
65
64
|
handleSignPayload: InferHandler<'v1', HostApiProtocol['sign_payload']>;
|
|
66
|
-
|
|
65
|
+
handleChatCreateRoom: InferHandler<'v1', HostApiProtocol['chat_create_room']>;
|
|
66
|
+
handleChatListSubscribe: InferHandler<'v1', HostApiProtocol['chat_list_subscribe']>;
|
|
67
67
|
handleChatPostMessage: InferHandler<'v1', HostApiProtocol['chat_post_message']>;
|
|
68
68
|
handleChatActionSubscribe: InferHandler<'v1', HostApiProtocol['chat_action_subscribe']>;
|
|
69
|
+
handleStatementStoreQuery: InferHandler<'v1', HostApiProtocol['statement_store_query']>;
|
|
70
|
+
handleStatementStoreSubscribe: InferHandler<'v1', HostApiProtocol['statement_store_subscribe']>;
|
|
69
71
|
handleStatementStoreCreateProof: InferHandler<'v1', HostApiProtocol['statement_store_create_proof']>;
|
|
72
|
+
handleStatementStoreSubmit: InferHandler<'v1', HostApiProtocol['statement_store_submit']>;
|
|
70
73
|
handleJsonRpcMessageSubscribe: (params: WithVersion<'v1', Value<HostApiProtocol['jsonrpc_message_subscribe']['start']>>, provider: JsonRpcProvider) => VoidFunction;
|
|
71
74
|
isReady(): Promise<boolean>;
|
|
72
75
|
dispose(): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novasamatech/host-container",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.4-0",
|
|
5
5
|
"description": "Host container for hosting and managing products within the Polkadot ecosystem.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -28,7 +28,11 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@polkadot-api/utils": "^0.2.0",
|
|
30
30
|
"@polkadot-api/json-rpc-provider": "^0.0.4",
|
|
31
|
-
"@novasamatech/host-api": "0.5.
|
|
31
|
+
"@novasamatech/host-api": "0.5.4-0",
|
|
32
|
+
"nanoid": "5.1.6"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"electron": "^40.1.0"
|
|
32
36
|
},
|
|
33
37
|
"publishConfig": {
|
|
34
38
|
"access": "public"
|