ewvjs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/bin/ewvjs-cli.js +318 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/js/api.js +256 -0
- package/dist/platforms/windows.d.ts +5 -0
- package/dist/platforms/windows.d.ts.map +1 -0
- package/dist/platforms/windows.js +143 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +22 -0
- package/dist/webview.d.ts +20 -0
- package/dist/webview.d.ts.map +1 -0
- package/dist/webview.js +92 -0
- package/dist/window.d.ts +55 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +307 -0
- package/lib/assets.js +129 -0
- package/lib/icon.js +150 -0
- package/lib/packager.js +347 -0
- package/native/Microsoft.Web.WebView2.Core.dll +0 -0
- package/native/Microsoft.Web.WebView2.WinForms.dll +0 -0
- package/native/Microsoft.Web.WebView2.Wpf.dll +0 -0
- package/native/WebView.cjs +26 -0
- package/native/WebView.d.ts +8 -0
- package/native/WebView.deps.json +260 -0
- package/native/WebView.dll +0 -0
- package/native/WebView.mjs +31 -0
- package/native/import.cjs +3 -0
- package/native/node_modules/node-api-dotnet/README.md +80 -0
- package/native/node_modules/node-api-dotnet/index.d.ts +98 -0
- package/native/node_modules/node-api-dotnet/index.js +2 -0
- package/native/node_modules/node-api-dotnet/init.js +80 -0
- package/native/node_modules/node-api-dotnet/linux-arm64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/node_modules/node-api-dotnet/linux-x64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/node_modules/node-api-dotnet/net10.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll +0 -0
- package/native/node_modules/node-api-dotnet/net10.0/Microsoft.JavaScript.NodeApi.dll +0 -0
- package/native/node_modules/node-api-dotnet/net10.0/Microsoft.JavaScript.NodeApi.runtimeconfig.json +14 -0
- package/native/node_modules/node-api-dotnet/net10.0.js +2 -0
- package/native/node_modules/node-api-dotnet/net472/Microsoft.Bcl.AsyncInterfaces.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472/Microsoft.JavaScript.NodeApi.DotNetHost.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472/Microsoft.JavaScript.NodeApi.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472/Microsoft.JavaScript.NodeApi.runtimeconfig.json +9 -0
- package/native/node_modules/node-api-dotnet/net472/System.Memory.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472/System.Runtime.CompilerServices.Unsafe.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472/System.Threading.Tasks.Extensions.dll +0 -0
- package/native/node_modules/node-api-dotnet/net472.d.ts +2 -0
- package/native/node_modules/node-api-dotnet/net472.js +2 -0
- package/native/node_modules/node-api-dotnet/net8.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll +0 -0
- package/native/node_modules/node-api-dotnet/net8.0/Microsoft.JavaScript.NodeApi.dll +0 -0
- package/native/node_modules/node-api-dotnet/net8.0/Microsoft.JavaScript.NodeApi.runtimeconfig.json +14 -0
- package/native/node_modules/node-api-dotnet/net8.0.d.ts +2 -0
- package/native/node_modules/node-api-dotnet/net8.0.js +2 -0
- package/native/node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.DotNetHost.dll +0 -0
- package/native/node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.dll +0 -0
- package/native/node_modules/node-api-dotnet/net9.0/Microsoft.JavaScript.NodeApi.runtimeconfig.json +14 -0
- package/native/node_modules/node-api-dotnet/net9.0.d.ts +2 -0
- package/native/node_modules/node-api-dotnet/net9.0.js +2 -0
- package/native/node_modules/node-api-dotnet/osx-arm64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/node_modules/node-api-dotnet/osx-x64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/node_modules/node-api-dotnet/package.json +27 -0
- package/native/node_modules/node-api-dotnet/win-arm64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/node_modules/node-api-dotnet/win-x64/Microsoft.JavaScript.NodeApi.node +0 -0
- package/native/runtimes/win-arm64/native/WebView2Loader.dll +0 -0
- package/native/runtimes/win-x64/native/WebView2Loader.dll +0 -0
- package/native/runtimes/win-x86/native/WebView2Loader.dll +0 -0
- package/package.json +57 -0
- package/src/README.md +125 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.Core.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.Core.xml +6817 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.WinForms.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.WinForms.xml +510 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.Wpf.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/Microsoft.Web.WebView2.Wpf.xml +1902 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.cjs +26 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.d.ts +8 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.deps.json +260 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.mjs +31 -0
- package/src/csharp/bin/Release/net10.0-windows/WebView.pdb +0 -0
- package/src/csharp/bin/Release/net10.0-windows/import.cjs +3 -0
- package/src/csharp/bin/Release/net10.0-windows/runtimes/win-arm64/native/WebView2Loader.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/runtimes/win-x64/native/WebView2Loader.dll +0 -0
- package/src/csharp/bin/Release/net10.0-windows/runtimes/win-x86/native/WebView2Loader.dll +0 -0
package/dist/window.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Window = void 0;
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
class Window {
|
|
15
|
+
constructor(platform, options, exposedFunctions) {
|
|
16
|
+
this._menuCallbacks = new Map();
|
|
17
|
+
this.on_context_menu = () => null;
|
|
18
|
+
this.platform = platform;
|
|
19
|
+
this.options = Object.assign({}, options);
|
|
20
|
+
this._exposedFunctions = exposedFunctions;
|
|
21
|
+
this._closedPromise = new Promise((resolve) => {
|
|
22
|
+
this._resolveClosed = resolve;
|
|
23
|
+
});
|
|
24
|
+
const originalCallback = this.options.jsCallback;
|
|
25
|
+
this.options.jsCallback = (msg) => __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
const result = yield this._on_message(msg, this._exposedFunctions);
|
|
27
|
+
if (originalCallback)
|
|
28
|
+
yield originalCallback(msg);
|
|
29
|
+
return result;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
get closed() {
|
|
33
|
+
return this._closedPromise;
|
|
34
|
+
}
|
|
35
|
+
run() {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
this.controller = yield this.platform.createWindow(this.options);
|
|
38
|
+
// Inject exposed functions API
|
|
39
|
+
const funcList = Object.keys(this._exposedFunctions).map(name => {
|
|
40
|
+
return { func: name, params: (0, utils_1.getParamNames)(this._exposedFunctions[name]) };
|
|
41
|
+
});
|
|
42
|
+
if (funcList.length > 0) {
|
|
43
|
+
const code = `if (window.ewvjs) { window.ewvjs._createApi(${JSON.stringify(funcList)}); }`;
|
|
44
|
+
setTimeout(() => this.evaluate_js(code).catch((err) => {
|
|
45
|
+
console.error('Failed to inject exposed functions API:', err);
|
|
46
|
+
}), 500);
|
|
47
|
+
}
|
|
48
|
+
return this.controller;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
_call(method_1) {
|
|
52
|
+
return __awaiter(this, arguments, void 0, function* (method, payload = null) {
|
|
53
|
+
if (!this.controller || !this.controller[method]) {
|
|
54
|
+
throw new Error(`Window not running or ${method} not supported`);
|
|
55
|
+
}
|
|
56
|
+
const result = this.controller[method](payload);
|
|
57
|
+
// Check if method returns a Promise (node-api-dotnet JSCallback style)
|
|
58
|
+
if (result && typeof result.then === 'function') {
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Core methods
|
|
67
|
+
evaluate_js(script) {
|
|
68
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
return this._call('evaluate', script);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
evaluate(script) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
return this.evaluate_js(script);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
close() {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
return this._call('close');
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
destroy() {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
return this._call('close');
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Window state methods
|
|
88
|
+
maximize() {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('maximize'); });
|
|
90
|
+
}
|
|
91
|
+
restore() {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('restore'); });
|
|
93
|
+
}
|
|
94
|
+
minimize() {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('minimize'); });
|
|
96
|
+
}
|
|
97
|
+
focus() {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('focus'); });
|
|
99
|
+
}
|
|
100
|
+
blur() {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('blur'); });
|
|
102
|
+
}
|
|
103
|
+
show() {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('show'); });
|
|
105
|
+
}
|
|
106
|
+
hide() {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('hide'); });
|
|
108
|
+
}
|
|
109
|
+
// Size and position methods
|
|
110
|
+
getSize() {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('getSize'); });
|
|
112
|
+
}
|
|
113
|
+
setSize(width, height) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
return this._call('setSize', { width, height });
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
resize(width, height) {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
return this._call('setSize', { width, height });
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
getPosition() {
|
|
124
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('getPosition'); });
|
|
125
|
+
}
|
|
126
|
+
setPosition(x, y) {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
return this._call('setPosition', { x, y });
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
move(x, y) {
|
|
132
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
+
return this._call('move', { x, y });
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
get_position() {
|
|
137
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('getPosition'); });
|
|
138
|
+
}
|
|
139
|
+
set_position(x, y) {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
+
return this._call('setPosition', { x, y });
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
get_width() {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
const size = yield this._call('getSize');
|
|
147
|
+
return size.width;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
get_height() {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
const size = yield this._call('getSize');
|
|
153
|
+
return size.height;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// Title methods
|
|
157
|
+
setTitle(title) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
return this._call('setTitle', title);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
set_title(title) {
|
|
163
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
164
|
+
return this._call('setTitle', title);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Title bar methods
|
|
168
|
+
show_titlebar() {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('setTitleBar', true); });
|
|
170
|
+
}
|
|
171
|
+
hide_titlebar() {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('setTitleBar', false); });
|
|
173
|
+
}
|
|
174
|
+
// Icon methods
|
|
175
|
+
setIcon(iconPath) {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
return this._call('setIcon', iconPath);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// Cookie methods
|
|
181
|
+
get_cookies() {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('getCookies'); });
|
|
183
|
+
}
|
|
184
|
+
set_cookie(name_1, value_1) {
|
|
185
|
+
return __awaiter(this, arguments, void 0, function* (name, value, domain = '', path = '/') {
|
|
186
|
+
return this._call('setCookie', { name, value, domain, path });
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
clear_cookies() {
|
|
190
|
+
return __awaiter(this, void 0, void 0, function* () { return this._call('clearCookies'); });
|
|
191
|
+
}
|
|
192
|
+
_on_message(message, exposedFunctions) {
|
|
193
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
194
|
+
try {
|
|
195
|
+
const data = typeof message === 'string' ? JSON.parse(message) : message;
|
|
196
|
+
if (!Array.isArray(data))
|
|
197
|
+
return null;
|
|
198
|
+
const funcName = data[0];
|
|
199
|
+
const rawParams = data[1];
|
|
200
|
+
const id = data[2];
|
|
201
|
+
const params = this._parseParams(rawParams);
|
|
202
|
+
// Handle special messages
|
|
203
|
+
if (funcName === 'closed') {
|
|
204
|
+
this._resolveClosed();
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
if (funcName === 'console') {
|
|
208
|
+
console.log('WebView Console:', ...params);
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
if (funcName === 'menu_click') {
|
|
212
|
+
return this._handleMenuClick(params);
|
|
213
|
+
}
|
|
214
|
+
if (funcName === 'context_menu_requested') {
|
|
215
|
+
return this._handleContextMenu(params);
|
|
216
|
+
}
|
|
217
|
+
// Handle exposed function calls
|
|
218
|
+
return this._handleExposedFunction(funcName, params, id, exposedFunctions);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
_parseParams(rawParams) {
|
|
226
|
+
let params = [];
|
|
227
|
+
if (rawParams) {
|
|
228
|
+
if (typeof rawParams === 'string' && (rawParams.startsWith('[') || rawParams.startsWith('{'))) {
|
|
229
|
+
try {
|
|
230
|
+
const parsed = JSON.parse(rawParams);
|
|
231
|
+
params = Array.isArray(parsed) ? parsed : [parsed];
|
|
232
|
+
}
|
|
233
|
+
catch (e) {
|
|
234
|
+
params = [rawParams];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
params = Array.isArray(rawParams) ? rawParams : [rawParams];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return params;
|
|
242
|
+
}
|
|
243
|
+
_handleMenuClick(params) {
|
|
244
|
+
const callbackId = params[0];
|
|
245
|
+
const callback = this._menuCallbacks.get(callbackId);
|
|
246
|
+
if (callback)
|
|
247
|
+
callback();
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
_handleContextMenu(params) {
|
|
251
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
+
if (this.on_context_menu) {
|
|
253
|
+
const customMenu = yield this.on_context_menu(params);
|
|
254
|
+
if (customMenu) {
|
|
255
|
+
return this._processMenu(customMenu);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
_handleExposedFunction(funcName, params, id, exposedFunctions) {
|
|
262
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
const func = exposedFunctions[funcName];
|
|
264
|
+
if (!func)
|
|
265
|
+
return null;
|
|
266
|
+
try {
|
|
267
|
+
const result = yield func(...params);
|
|
268
|
+
yield this._sendSuccessResponse(funcName, id, result);
|
|
269
|
+
return result !== undefined ? result : null;
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
yield this._sendErrorResponse(funcName, id, err);
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
_sendSuccessResponse(funcName, id, result) {
|
|
278
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
const resJson = JSON.stringify(result);
|
|
280
|
+
const code = `window.ewvjs._returnValuesCallbacks["${funcName}"]["${id}"]({value: ${JSON.stringify(resJson)}, isError: false})`;
|
|
281
|
+
yield this.evaluate_js(code);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
_sendErrorResponse(funcName, id, err) {
|
|
285
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
286
|
+
const errObj = { message: err.message, name: err.name, stack: err.stack };
|
|
287
|
+
const code = `window.ewvjs._returnValuesCallbacks["${funcName}"]["${id}"]({value: ${JSON.stringify(JSON.stringify(errObj))}, isError: true})`;
|
|
288
|
+
yield this.evaluate_js(code);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
_processMenu(menu) {
|
|
292
|
+
return menu.map((item) => {
|
|
293
|
+
const newItem = Object.assign({}, item);
|
|
294
|
+
if (newItem.click) {
|
|
295
|
+
const id = newItem.id || (0, utils_1.generateId)();
|
|
296
|
+
newItem.id = id;
|
|
297
|
+
this._menuCallbacks.set(id, newItem.click);
|
|
298
|
+
delete newItem.click;
|
|
299
|
+
}
|
|
300
|
+
if (newItem.submenu) {
|
|
301
|
+
newItem.submenu = this._processMenu(newItem.submenu);
|
|
302
|
+
}
|
|
303
|
+
return newItem;
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
exports.Window = Window;
|
package/lib/assets.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const archiver = require('archiver');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bundle assets directory
|
|
7
|
+
* @param {string} assetsDir - Source assets directory
|
|
8
|
+
* @param {string} outputDir - Destination directory
|
|
9
|
+
* @returns {Promise<void>}
|
|
10
|
+
*/
|
|
11
|
+
async function bundleAssets(assetsDir, outputDir) {
|
|
12
|
+
if (!fs.existsSync(assetsDir)) {
|
|
13
|
+
throw new Error(`Assets directory not found: ${assetsDir}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Create output directory
|
|
17
|
+
if (!fs.existsSync(outputDir)) {
|
|
18
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Copy assets directory
|
|
22
|
+
await copyDirectory(assetsDir, outputDir);
|
|
23
|
+
|
|
24
|
+
// Get stats
|
|
25
|
+
const stats = getDirectoryStats(outputDir);
|
|
26
|
+
console.log(` Copied ${stats.files} files (${formatBytes(stats.size)})`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Copy directory recursively
|
|
31
|
+
* @param {string} src - Source directory
|
|
32
|
+
* @param {string} dest - Destination directory
|
|
33
|
+
*/
|
|
34
|
+
async function copyDirectory(src, dest) {
|
|
35
|
+
if (!fs.existsSync(dest)) {
|
|
36
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
40
|
+
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const srcPath = path.join(src, entry.name);
|
|
43
|
+
const destPath = path.join(dest, entry.name);
|
|
44
|
+
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
await copyDirectory(srcPath, destPath);
|
|
47
|
+
} else {
|
|
48
|
+
fs.copyFileSync(srcPath, destPath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a zip archive of assets (alternative to direct copy)
|
|
55
|
+
* @param {string} assetsDir - Source assets directory
|
|
56
|
+
* @param {string} outputPath - Output zip file path
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
*/
|
|
59
|
+
async function createAssetsArchive(assetsDir, outputPath) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const output = fs.createWriteStream(outputPath);
|
|
62
|
+
const archive = archiver('zip', {
|
|
63
|
+
zlib: { level: 9 } // Maximum compression
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
output.on('close', () => {
|
|
67
|
+
console.log(` Created archive: ${formatBytes(archive.pointer())}`);
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
archive.on('error', (err) => {
|
|
72
|
+
reject(err);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
archive.pipe(output);
|
|
76
|
+
archive.directory(assetsDir, false);
|
|
77
|
+
archive.finalize();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get directory statistics
|
|
83
|
+
* @param {string} dirPath - Directory path
|
|
84
|
+
* @returns {{files: number, size: number}}
|
|
85
|
+
*/
|
|
86
|
+
function getDirectoryStats(dirPath) {
|
|
87
|
+
let fileCount = 0;
|
|
88
|
+
let totalSize = 0;
|
|
89
|
+
|
|
90
|
+
function traverse(dir) {
|
|
91
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
92
|
+
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
const fullPath = path.join(dir, entry.name);
|
|
95
|
+
|
|
96
|
+
if (entry.isDirectory()) {
|
|
97
|
+
traverse(fullPath);
|
|
98
|
+
} else {
|
|
99
|
+
fileCount++;
|
|
100
|
+
totalSize += fs.statSync(fullPath).size;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
traverse(dirPath);
|
|
106
|
+
return { files: fileCount, size: totalSize };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Format bytes to human-readable string
|
|
111
|
+
* @param {number} bytes - Number of bytes
|
|
112
|
+
* @returns {string}
|
|
113
|
+
*/
|
|
114
|
+
function formatBytes(bytes) {
|
|
115
|
+
if (bytes === 0) return '0 Bytes';
|
|
116
|
+
|
|
117
|
+
const k = 1024;
|
|
118
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
119
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
120
|
+
|
|
121
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
bundleAssets,
|
|
126
|
+
createAssetsArchive,
|
|
127
|
+
copyDirectory,
|
|
128
|
+
formatBytes
|
|
129
|
+
};
|
package/lib/icon.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const NtExecutable = require('resedit').NtExecutable;
|
|
4
|
+
const NtExecutableResource = require('resedit').NtExecutableResource;
|
|
5
|
+
const Resource = require('resedit').Resource;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Set icon and metadata for Windows executable
|
|
9
|
+
* @param {string} exePath - Path to the executable
|
|
10
|
+
* @param {string} iconPath - Path to the .ico file
|
|
11
|
+
* @param {string} appName - Application name
|
|
12
|
+
* @param {Object} options - Additional metadata options
|
|
13
|
+
* @returns {Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
async function setIcon(exePath, iconPath, appName, options = {}) {
|
|
16
|
+
try {
|
|
17
|
+
// Read the executable
|
|
18
|
+
const exeBuffer = fs.readFileSync(exePath);
|
|
19
|
+
const exe = NtExecutable.from(exeBuffer);
|
|
20
|
+
const res = NtExecutableResource.from(exe);
|
|
21
|
+
|
|
22
|
+
// Read the icon file
|
|
23
|
+
if (iconPath && fs.existsSync(iconPath)) {
|
|
24
|
+
const iconBuffer = fs.readFileSync(iconPath);
|
|
25
|
+
|
|
26
|
+
// Parse icon data
|
|
27
|
+
const iconFile = Resource.IconFile.from(iconBuffer);
|
|
28
|
+
|
|
29
|
+
// Replace icon in executable
|
|
30
|
+
Resource.IconGroupEntry.replaceIconsForResource(
|
|
31
|
+
res.entries,
|
|
32
|
+
1, // Icon group ID
|
|
33
|
+
1033, // Language (English - United States)
|
|
34
|
+
iconFile.icons.map((icon) => icon.data)
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
console.log(` Applied icon: ${path.basename(iconPath)}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Set version info
|
|
41
|
+
const viList = Resource.VersionInfo.fromEntries(res.entries);
|
|
42
|
+
const vi = viList[0] || Resource.VersionInfo.createEmpty();
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
version = '1.0.0.0',
|
|
46
|
+
companyName = '',
|
|
47
|
+
fileDescription = appName,
|
|
48
|
+
copyright = `Copyright © ${new Date().getFullYear()}`,
|
|
49
|
+
productName = appName,
|
|
50
|
+
internalName = appName.replace(/\s+/g, ''),
|
|
51
|
+
} = options;
|
|
52
|
+
|
|
53
|
+
// Parse version string
|
|
54
|
+
const [major = 1, minor = 0, patch = 0, build = 0] = version.split('.').map(Number);
|
|
55
|
+
|
|
56
|
+
// Set version numbers
|
|
57
|
+
vi.setFileVersion(major, minor, patch, build, 1033);
|
|
58
|
+
vi.setProductVersion(major, minor, patch, build, 1033);
|
|
59
|
+
|
|
60
|
+
// Set string values
|
|
61
|
+
vi.setStringValues(
|
|
62
|
+
{ lang: 1033, codepage: 1200 },
|
|
63
|
+
{
|
|
64
|
+
ProductName: productName,
|
|
65
|
+
FileDescription: fileDescription,
|
|
66
|
+
CompanyName: companyName,
|
|
67
|
+
LegalCopyright: copyright,
|
|
68
|
+
FileVersion: version,
|
|
69
|
+
ProductVersion: version,
|
|
70
|
+
InternalName: internalName,
|
|
71
|
+
OriginalFilename: path.basename(exePath)
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
vi.outputToResourceEntries(res.entries);
|
|
76
|
+
|
|
77
|
+
// Write back to executable
|
|
78
|
+
res.outputResource(exe);
|
|
79
|
+
const newBuffer = exe.generate();
|
|
80
|
+
fs.writeFileSync(exePath, Buffer.from(newBuffer));
|
|
81
|
+
|
|
82
|
+
console.log(` Applied metadata: ${appName} v${version}`);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.warn(` ⚠ Warning: Could not set icon/metadata: ${error.message}`);
|
|
85
|
+
console.warn(' The executable was created but icon/metadata may be missing.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validate icon file
|
|
91
|
+
* @param {string} iconPath - Path to icon file
|
|
92
|
+
* @returns {boolean}
|
|
93
|
+
*/
|
|
94
|
+
function validateIcon(iconPath) {
|
|
95
|
+
if (!fs.existsSync(iconPath)) {
|
|
96
|
+
throw new Error(`Icon file not found: ${iconPath}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!iconPath.toLowerCase().endsWith('.ico')) {
|
|
100
|
+
throw new Error('Icon file must be in .ico format');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const stats = fs.statSync(iconPath);
|
|
104
|
+
if (stats.size === 0) {
|
|
105
|
+
throw new Error('Icon file is empty');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (stats.size > 1024 * 1024) {
|
|
109
|
+
console.warn('Warning: Icon file is larger than 1MB, consider optimizing it');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extract icon from executable
|
|
117
|
+
* @param {string} exePath - Path to executable
|
|
118
|
+
* @param {string} outputPath - Output path for icon file
|
|
119
|
+
* @returns {Promise<void>}
|
|
120
|
+
*/
|
|
121
|
+
async function extractIcon(exePath, outputPath) {
|
|
122
|
+
try {
|
|
123
|
+
const exeBuffer = fs.readFileSync(exePath);
|
|
124
|
+
const exe = NtExecutable.from(exeBuffer);
|
|
125
|
+
const res = NtExecutableResource.from(exe);
|
|
126
|
+
|
|
127
|
+
// Find icon group
|
|
128
|
+
const iconGroups = Resource.IconGroupEntry.fromEntries(res.entries);
|
|
129
|
+
|
|
130
|
+
if (iconGroups.length === 0) {
|
|
131
|
+
throw new Error('No icon found in executable');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Get first icon group
|
|
135
|
+
const iconGroup = iconGroups[0];
|
|
136
|
+
const iconFile = Resource.IconFile.from(iconGroup, res.entries);
|
|
137
|
+
|
|
138
|
+
// Write icon file
|
|
139
|
+
fs.writeFileSync(outputPath, Buffer.from(iconFile.data));
|
|
140
|
+
console.log(`Extracted icon to: ${outputPath}`);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
throw new Error(`Failed to extract icon: ${error.message}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
setIcon,
|
|
148
|
+
validateIcon,
|
|
149
|
+
extractIcon
|
|
150
|
+
};
|