electron-incremental-update 1.0.3 → 1.2.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/vite.js CHANGED
@@ -1,74 +1,42 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key2 of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key2) && key2 !== except)
16
- __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
1
  // src/vite.ts
31
- var vite_exports = {};
32
- __export(vite_exports, {
33
- debugStartup: () => debugStartup,
34
- electronWithUpdater: () => electronWithUpdater,
35
- log: () => log
36
- });
37
- module.exports = __toCommonJS(vite_exports);
38
- var import_node_path3 = require("path");
39
- var import_node_fs4 = require("fs");
40
- var import_vite3 = require("vite");
41
- var import_simple = __toESM(require("vite-plugin-electron/simple"));
42
- var import_vite_plugin_electron = require("vite-plugin-electron");
43
- var import_plugin = require("vite-plugin-electron/plugin");
2
+ import { basename as basename2, join as join2, resolve } from "node:path";
3
+ import { cpSync, existsSync as existsSync4, rmSync as rmSync2 } from "node:fs";
4
+ import { mergeConfig as mergeConfig2, normalizePath as normalizePath2 } from "vite";
5
+ import ElectronSimple from "vite-plugin-electron/simple";
6
+ import { startup } from "vite-plugin-electron";
7
+ import { notBundle } from "vite-plugin-electron/plugin";
8
+ import { loadPackageJSON } from "local-pkg";
44
9
 
45
10
  // src/build-plugins/build.ts
46
- var import_promises = require("fs/promises");
47
- var import_node_fs2 = require("fs");
48
- var import_node_path = require("path");
49
- var import_asar = __toESM(require("@electron/asar"));
50
- var import_esbuild = require("esbuild");
11
+ import { existsSync as existsSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
12
+ import { basename, join } from "node:path";
13
+ import Asar from "@electron/asar";
14
+ import { build } from "esbuild";
15
+ import { mergeConfig } from "vite";
16
+
17
+ // src/crypto/utils.ts
18
+ import { createHash } from "node:crypto";
19
+ function hashString(data, length) {
20
+ const hash = createHash("SHA256").update(data).digest("binary");
21
+ return Buffer.from(hash).subarray(0, length);
22
+ }
51
23
 
52
- // src/crypto.ts
53
- var import_node_crypto = require("crypto");
54
- function encrypt(plainText, key2, iv) {
55
- const cipher = (0, import_node_crypto.createCipheriv)("aes-256-cbc", key2, iv);
24
+ // src/crypto/enc.ts
25
+ import { createCipheriv, createPrivateKey, createSign } from "node:crypto";
26
+ function encrypt(plainText, key, iv) {
27
+ const cipher = createCipheriv("aes-256-cbc", key, iv);
56
28
  let encrypted = cipher.update(plainText, "utf8", "base64url");
57
29
  encrypted += cipher.final("base64url");
58
30
  return encrypted;
59
31
  }
60
- function key(data, length) {
61
- const hash = (0, import_node_crypto.createHash)("SHA256").update(data).digest("binary");
62
- return Buffer.from(hash).subarray(0, length);
63
- }
64
32
  var signature = (buffer, privateKey, cert, version) => {
65
- const sig = (0, import_node_crypto.createSign)("RSA-SHA256").update(buffer).sign((0, import_node_crypto.createPrivateKey)(privateKey), "base64");
66
- return encrypt(`${sig}%${version}`, key(cert, 32), key(buffer, 16));
33
+ const sig = createSign("RSA-SHA256").update(buffer).sign(createPrivateKey(privateKey), "base64");
34
+ return encrypt(`${sig}%${version}`, hashString(cert, 32), hashString(buffer, 16));
67
35
  };
68
36
 
69
- // src/utils/noDep.ts
37
+ // src/utils/pure.ts
70
38
  function parseVersion(version) {
71
- const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\.-]+))?/i;
39
+ const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-z0-9.-]+))?/i;
72
40
  const match = semver.exec(version);
73
41
  if (!match) {
74
42
  throw new TypeError(`invalid version: ${version}`);
@@ -97,24 +65,212 @@ function isUpdateJSON(json) {
97
65
  }
98
66
 
99
67
  // src/utils/zip.ts
100
- var import_node_fs = require("fs");
101
- var import_node_zlib = require("zlib");
68
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
69
+ import { brotliCompress, brotliDecompress } from "node:zlib";
102
70
  async function zipFile(filePath, targetFilePath = `${filePath}.gz`) {
103
- if (!(0, import_node_fs.existsSync)(filePath)) {
71
+ if (!existsSync(filePath)) {
104
72
  throw new Error(`path to be zipped not exist: ${filePath}`);
105
73
  }
106
- const buffer = (0, import_node_fs.readFileSync)(filePath);
74
+ const buffer = readFileSync(filePath);
107
75
  return new Promise((resolve2, reject) => {
108
- (0, import_node_zlib.gzip)(buffer, (err, buffer2) => {
76
+ brotliCompress(buffer, (err, buffer2) => {
109
77
  if (err) {
110
78
  reject(err);
111
79
  }
112
- (0, import_node_fs.writeFileSync)(targetFilePath, buffer2);
80
+ writeFileSync(targetFilePath, buffer2);
113
81
  resolve2(null);
114
82
  });
115
83
  });
116
84
  }
117
85
 
86
+ // src/build-plugins/log.ts
87
+ import { createLogger } from "vite";
88
+
89
+ // src/build-plugins/constant.ts
90
+ var id = "electron-incremental-updater";
91
+ var bytecodeId = `${id}-bytecode`;
92
+ var loaderId = `${id}-loader`;
93
+
94
+ // src/build-plugins/log.ts
95
+ var log = createLogger("info", { prefix: `[${id}]` });
96
+ var bytecodeLog = createLogger("info", { prefix: `[${bytecodeId}]` });
97
+
98
+ // src/build-plugins/bytecode/code.ts
99
+ var bytecodeGeneratorScript = "const vm = require('vm')\nconst v8 = require('v8')\nconst wrap = require('module').wrap\nv8.setFlagsFromString('--no-lazy')\nv8.setFlagsFromString('--no-flush-bytecode')\nlet code = ''\nprocess.stdin.setEncoding('utf-8')\nprocess.stdin.on('readable', () => {\n const data = process.stdin.read()\n if (data !== null) {\n code += data\n }\n})\nprocess.stdin.on('end', () => {\n try {\n if (typeof code !== 'string') {\n throw new Error('javascript code must be string.')\n }\n const script = new vm.Script(wrap(code), { produceCachedData: true })\n const bytecodeBuffer = script.createCachedData()\n process.stdout.write(bytecodeBuffer)\n } catch (error) {\n console.error(error)\n }\n})\n";
100
+ var bytecodeModuleLoaderCode = [
101
+ `"use strict";`,
102
+ `const fs = require("fs");`,
103
+ `const path = require("path");`,
104
+ `const vm = require("vm");`,
105
+ `const v8 = require("v8");`,
106
+ `const Module = require("module");`,
107
+ `v8.setFlagsFromString("--no-lazy");`,
108
+ `v8.setFlagsFromString("--no-flush-bytecode");`,
109
+ `const FLAG_HASH_OFFSET = 12;`,
110
+ `const SOURCE_HASH_OFFSET = 8;`,
111
+ `let dummyBytecode;`,
112
+ `function setFlagHashHeader(bytecodeBuffer) {`,
113
+ ` if (!dummyBytecode) {`,
114
+ ` const script = new vm.Script("", {`,
115
+ ` produceCachedData: true`,
116
+ ` });`,
117
+ ` dummyBytecode = script.createCachedData();`,
118
+ ` }`,
119
+ ` dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);`,
120
+ `};`,
121
+ `function getSourceHashHeader(bytecodeBuffer) {`,
122
+ ` return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);`,
123
+ `};`,
124
+ `function buffer2Number(buffer) {`,
125
+ ` let ret = 0;`,
126
+ ` ret |= buffer[3] << 24;`,
127
+ ` ret |= buffer[2] << 16;`,
128
+ ` ret |= buffer[1] << 8;`,
129
+ ` ret |= buffer[0];`,
130
+ ` return ret;`,
131
+ `};`,
132
+ `Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {`,
133
+ ` const bytecodeBuffer = fs.readFileSync(filename);`,
134
+ ` if (!Buffer.isBuffer(bytecodeBuffer)) {`,
135
+ ` throw new Error("BytecodeBuffer must be a buffer object.");`,
136
+ ` }`,
137
+ ` setFlagHashHeader(bytecodeBuffer);`,
138
+ ` const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));`,
139
+ ` let dummyCode = "";`,
140
+ ` if (length > 1) {`,
141
+ ` dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";`,
142
+ ` }`,
143
+ ` const script = new vm.Script(dummyCode, {`,
144
+ ` filename: filename,`,
145
+ ` lineOffset: 0,`,
146
+ ` displayErrors: true,`,
147
+ ` cachedData: bytecodeBuffer`,
148
+ ` });`,
149
+ ` if (script.cachedDataRejected) {`,
150
+ ` throw new Error("Invalid or incompatible cached data (cachedDataRejected)");`,
151
+ ` }`,
152
+ ` const require = function (id) {`,
153
+ ` return module.require(id);`,
154
+ ` };`,
155
+ ` require.resolve = function (request, options) {`,
156
+ ` return Module._resolveFilename(request, module, false, options);`,
157
+ ` };`,
158
+ ` if (process.mainModule) {`,
159
+ ` require.main = process.mainModule;`,
160
+ ` }`,
161
+ ` require.extensions = Module._extensions;`,
162
+ ` require.cache = Module._cache;`,
163
+ ` const compiledWrapper = script.runInThisContext({`,
164
+ ` filename: filename,`,
165
+ ` lineOffset: 0,`,
166
+ ` columnOffset: 0,`,
167
+ ` displayErrors: true`,
168
+ ` });`,
169
+ ` const dirname = path.dirname(filename);`,
170
+ ` const args = [module.exports, require, module, filename, dirname, process, global];`,
171
+ ` return compiledWrapper.apply(module.exports, args);`,
172
+ `};`
173
+ ].join("\n");
174
+
175
+ // src/build-plugins/bytecode/utils.ts
176
+ import path from "node:path";
177
+ import fs from "node:fs";
178
+ import { spawn } from "node:child_process";
179
+ import * as babel from "@babel/core";
180
+ import MagicString from "magic-string";
181
+ import { getPackageInfoSync } from "local-pkg";
182
+ var electronModulePath = getPackageInfoSync("electron")?.rootPath;
183
+ var useStrict = "'use strict';";
184
+ var bytecodeModuleLoader = "__loader__.js";
185
+ function getElectronPath() {
186
+ let electronExecPath = process.env.ELECTRON_EXEC_PATH || "";
187
+ if (!electronExecPath) {
188
+ if (!electronModulePath) {
189
+ throw new Error("Electron is not installed");
190
+ }
191
+ const pathFile = path.join(electronModulePath, "path.txt");
192
+ let executablePath;
193
+ if (fs.existsSync(pathFile)) {
194
+ executablePath = fs.readFileSync(pathFile, "utf-8");
195
+ }
196
+ if (executablePath) {
197
+ electronExecPath = path.join(electronModulePath, "dist", executablePath);
198
+ process.env.ELECTRON_EXEC_PATH = electronExecPath;
199
+ } else {
200
+ throw new Error("Electron executable file is not existed");
201
+ }
202
+ }
203
+ return electronExecPath;
204
+ }
205
+ function getBytecodeCompilerPath() {
206
+ const scriptPath = path.join(electronModulePath, "bytenode.cjs");
207
+ if (!fs.existsSync(scriptPath)) {
208
+ fs.writeFileSync(scriptPath, bytecodeGeneratorScript);
209
+ }
210
+ return scriptPath;
211
+ }
212
+ function toRelativePath(filename, importer) {
213
+ const relPath = path.posix.relative(path.dirname(importer), filename);
214
+ return relPath.startsWith(".") ? relPath : `./${relPath}`;
215
+ }
216
+ function compileToBytecode(code) {
217
+ let data = Buffer.from([]);
218
+ const logErr = (...args) => log.error(args.join(" "), { timestamp: true });
219
+ const electronPath = getElectronPath();
220
+ const bytecodePath = getBytecodeCompilerPath();
221
+ return new Promise((resolve2, reject) => {
222
+ const proc = spawn(electronPath, [bytecodePath], {
223
+ env: { ELECTRON_RUN_AS_NODE: "1" },
224
+ stdio: ["pipe", "pipe", "pipe", "ipc"]
225
+ });
226
+ if (proc.stdin) {
227
+ proc.stdin.write(code);
228
+ proc.stdin.end();
229
+ }
230
+ if (proc.stdout) {
231
+ proc.stdout.on("data", (chunk) => data = Buffer.concat([data, chunk]));
232
+ proc.stdout.on("error", (err) => logErr(err));
233
+ proc.stdout.on("end", () => resolve2(data));
234
+ }
235
+ if (proc.stderr) {
236
+ proc.stderr.on("data", (chunk) => logErr("Error: ", chunk.toString()));
237
+ proc.stderr.on("error", (err) => logErr("Error: ", err));
238
+ }
239
+ proc.addListener("error", (err) => logErr(err));
240
+ proc.on("error", (err) => reject(err));
241
+ proc.on("exit", () => resolve2(data));
242
+ });
243
+ }
244
+ function convertArrowToFunction(code) {
245
+ const result = babel.transform(code, {
246
+ plugins: ["@babel/plugin-transform-arrow-functions"]
247
+ });
248
+ return {
249
+ code: result?.code || code,
250
+ map: result?.map
251
+ };
252
+ }
253
+ function escapeRegExpString(str) {
254
+ return str.replace(/\\/g, "\\\\").replace(/[|{}()[\]^$+*?.]/g, "\\$&");
255
+ }
256
+ function convertString(code, strings, sourcemap) {
257
+ let s = null;
258
+ for (const str of strings.filter(Boolean)) {
259
+ const regex = new RegExp(`["']${escapeRegExpString(str)}["']`, "g");
260
+ s ||= new MagicString(code).replace(regex, (match) => obfuscateString(match.slice(1, -1)));
261
+ }
262
+ return s ? {
263
+ code: s.toString(),
264
+ map: sourcemap ? s.generateMap({ hires: "boundary" }) : null
265
+ } : { code };
266
+ }
267
+ function obfuscateString(input) {
268
+ const offset = Math.floor(Math.random() * 2 << 4) + 1;
269
+ const hexArray = Array.from(input).map((c) => "0x" + (c.charCodeAt(0) + offset).toString(16));
270
+ const decodeFn = `function(a,b){return String.fromCharCode.apply(null,a.map(x=>+x-b))}`;
271
+ return `(${decodeFn})([${hexArray.join(",")}],${offset})`;
272
+ }
273
+
118
274
  // src/build-plugins/build.ts
119
275
  async function buildAsar({
120
276
  version,
@@ -123,9 +279,9 @@ async function buildAsar({
123
279
  electronDistPath,
124
280
  rendererDistPath
125
281
  }) {
126
- await (0, import_promises.rename)(rendererDistPath, (0, import_node_path.join)(electronDistPath, "renderer"));
127
- await (0, import_promises.writeFile)((0, import_node_path.join)(electronDistPath, "version"), version);
128
- await import_asar.default.createPackage(electronDistPath, asarOutputPath);
282
+ renameSync(rendererDistPath, join(electronDistPath, "renderer"));
283
+ writeFileSync2(join(electronDistPath, "version"), version);
284
+ await Asar.createPackage(electronDistPath, asarOutputPath);
129
285
  await zipFile(asarOutputPath, gzipPath);
130
286
  }
131
287
  async function buildVersion({
@@ -150,9 +306,9 @@ async function buildVersion({
150
306
  size: 0,
151
307
  version
152
308
  };
153
- if ((0, import_node_fs2.existsSync)(versionPath)) {
309
+ if (existsSync2(versionPath)) {
154
310
  try {
155
- const oldVersionJson = JSON.parse(await (0, import_promises.readFile)(versionPath, "utf-8"));
311
+ const oldVersionJson = JSON.parse(readFileSync2(versionPath, "utf-8"));
156
312
  if (isUpdateJSON(oldVersionJson)) {
157
313
  _json = oldVersionJson;
158
314
  } else {
@@ -161,7 +317,7 @@ async function buildVersion({
161
317
  } catch (error) {
162
318
  }
163
319
  }
164
- const buffer = await (0, import_promises.readFile)(gzipPath);
320
+ const buffer = readFileSync2(gzipPath);
165
321
  const sig = await (generateSignature ?? signature)(buffer, privateKey, cert, version);
166
322
  if (generateVersionJson) {
167
323
  _json = await generateVersionJson(_json, buffer, sig, version, minimumVersion);
@@ -182,7 +338,7 @@ async function buildVersion({
182
338
  _json.size = buffer.length;
183
339
  }
184
340
  }
185
- await (0, import_promises.writeFile)(versionPath, JSON.stringify(_json, null, 2));
341
+ writeFileSync2(versionPath, JSON.stringify(_json, null, 2));
186
342
  }
187
343
  async function buildEntry({
188
344
  sourcemap,
@@ -191,83 +347,104 @@ async function buildEntry({
191
347
  entryOutputDirPath,
192
348
  nativeModuleEntryMap,
193
349
  overrideEsbuildOptions
194
- }) {
195
- await (0, import_esbuild.build)({
196
- entryPoints: {
197
- entry: appEntryPath,
198
- ...nativeModuleEntryMap
199
- },
200
- bundle: true,
201
- platform: "node",
202
- outdir: entryOutputDirPath,
203
- minify,
204
- sourcemap,
205
- entryNames: "[dir]/[name]",
206
- assetNames: "[dir]/[name]",
207
- external: ["electron", "original-fs"],
208
- loader: {
209
- ".node": "empty"
350
+ }, cert, protectedStrings) {
351
+ const option = mergeConfig(
352
+ {
353
+ entryPoints: {
354
+ entry: appEntryPath,
355
+ ...nativeModuleEntryMap
356
+ },
357
+ bundle: true,
358
+ metafile: true,
359
+ platform: "node",
360
+ outdir: entryOutputDirPath,
361
+ minify,
362
+ sourcemap,
363
+ entryNames: "[dir]/[name]",
364
+ assetNames: "[dir]/[name]",
365
+ external: ["electron", "original-fs"],
366
+ loader: {
367
+ ".node": "empty"
368
+ },
369
+ define: {
370
+ __SIGNATURE_CERT__: JSON.stringify(cert)
371
+ }
210
372
  },
211
- ...overrideEsbuildOptions
212
- });
373
+ overrideEsbuildOptions ?? {}
374
+ );
375
+ const { metafile } = await build(option);
376
+ if (protectedStrings === void 0) {
377
+ return;
378
+ }
379
+ const filePaths = Object.keys(metafile?.outputs ?? []);
380
+ for (const filePath of filePaths) {
381
+ let code = readFileSync2(filePath, "utf-8");
382
+ const fileName = basename(filePath);
383
+ const isEntry = fileName.endsWith("entry.js");
384
+ if (isEntry) {
385
+ code = code.replace(
386
+ /(`-----BEGIN CERTIFICATE-----[\s\S]*-----END CERTIFICATE-----\n`)/,
387
+ (_, cert2) => `"${cert2.slice(1, -1).replace(/\n/g, "\\n")}"`
388
+ );
389
+ }
390
+ const transformedCode = convertString(
391
+ convertArrowToFunction(code).code,
392
+ [...protectedStrings, ...isEntry ? getCert(code) : []]
393
+ ).code;
394
+ const buffer = await compileToBytecode(transformedCode);
395
+ writeFileSync2(`${filePath}c`, buffer);
396
+ writeFileSync2(
397
+ filePath,
398
+ `${isEntry ? bytecodeModuleLoaderCode : useStrict}${isEntry ? "" : "module.exports = "}require("./${fileName}c")`
399
+ );
400
+ bytecodeLog.info(
401
+ `${filePath} => ${(buffer.byteLength / 1e3).toFixed(2)} kB`,
402
+ { timestamp: true }
403
+ );
404
+ }
405
+ bytecodeLog.info(`${filePaths.length} bundles compiled into bytecode`, { timestamp: true });
406
+ }
407
+ function getCert(code) {
408
+ const cert = code.match(/-----BEGIN CERTIFICATE-----[\s\S]*-----END CERTIFICATE-----\\n/)?.[0];
409
+ return cert ? [cert] : [];
213
410
  }
214
411
 
215
412
  // src/build-plugins/key.ts
216
- var import_node_fs3 = require("fs");
217
- var import_node_path2 = require("path");
218
- var import_selfsigned = require("selfsigned");
413
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
414
+ import { dirname } from "node:path";
415
+ import { generate } from "selfsigned";
219
416
  function generateKeyPair(keyLength, subject, days, privateKeyPath, certPath) {
220
- const privateKeyDir = (0, import_node_path2.dirname)(privateKeyPath);
221
- if (!(0, import_node_fs3.existsSync)(privateKeyDir)) {
222
- (0, import_node_fs3.mkdirSync)(privateKeyDir, { recursive: true });
417
+ const privateKeyDir = dirname(privateKeyPath);
418
+ if (!existsSync3(privateKeyDir)) {
419
+ mkdirSync(privateKeyDir, { recursive: true });
223
420
  }
224
- const certDir = (0, import_node_path2.dirname)(certPath);
225
- if (!(0, import_node_fs3.existsSync)(certDir)) {
226
- (0, import_node_fs3.mkdirSync)(certDir, { recursive: true });
421
+ const certDir = dirname(certPath);
422
+ if (!existsSync3(certDir)) {
423
+ mkdirSync(certDir, { recursive: true });
227
424
  }
228
- const { cert, private: privateKey } = (0, import_selfsigned.generate)(subject, {
425
+ const { cert, private: privateKey } = generate(subject, {
229
426
  keySize: keyLength,
230
427
  algorithm: "sha256",
231
428
  days
232
429
  });
233
- (0, import_node_fs3.writeFileSync)(privateKeyPath, privateKey.replace(/\r\n?/g, "\n"));
234
- (0, import_node_fs3.writeFileSync)(certPath, cert.replace(/\r\n?/g, "\n"));
235
- }
236
- var noCertRegex = /(?<=const SIGNATURE_CERT\s*=\s*)['"]{2}/m;
237
- var existCertRegex = /(?<=const SIGNATURE_CERT\s*=\s*)(['"]-----BEGIN CERTIFICATE-----[\s\S]*-----END CERTIFICATE-----\\n['"])/m;
238
- function writeCertToEntry(entryPath, cert) {
239
- if (!(0, import_node_fs3.existsSync)(entryPath)) {
240
- throw new Error(`entry not exist: ${entryPath}`);
241
- }
242
- const file = (0, import_node_fs3.readFileSync)(entryPath, "utf-8");
243
- const replacement = cert.split("\n").filter(Boolean).map((s) => `'${s}\\n'`).join("\n + ");
244
- let replaced = file;
245
- if (noCertRegex.test(file)) {
246
- replaced = file.replace(noCertRegex, replacement);
247
- } else if (existCertRegex.test(file)) {
248
- replaced = file.replace(existCertRegex, replacement);
249
- } else {
250
- throw new Error("no `SIGNATURE_CERT` found in entry");
251
- }
252
- (0, import_node_fs3.writeFileSync)(entryPath, replaced);
430
+ writeFileSync3(privateKeyPath, privateKey.replace(/\r\n?/g, "\n"));
431
+ writeFileSync3(certPath, cert.replace(/\r\n?/g, "\n"));
253
432
  }
254
433
  function parseKeys({
255
434
  keyLength,
256
435
  privateKeyPath,
257
436
  certPath,
258
- appEntryPath,
259
437
  subject,
260
438
  days
261
439
  }) {
262
- const keysDir = (0, import_node_path2.dirname)(privateKeyPath);
263
- !(0, import_node_fs3.existsSync)(keysDir) && (0, import_node_fs3.mkdirSync)(keysDir);
264
- if (!(0, import_node_fs3.existsSync)(privateKeyPath) || !(0, import_node_fs3.existsSync)(certPath)) {
440
+ const keysDir = dirname(privateKeyPath);
441
+ !existsSync3(keysDir) && mkdirSync(keysDir);
442
+ if (!existsSync3(privateKeyPath) || !existsSync3(certPath)) {
265
443
  log.warn("no key pair found, generate new key pair");
266
444
  generateKeyPair(keyLength, parseSubjects(subject), days, privateKeyPath, certPath);
267
445
  }
268
- const privateKey = process.env.UPDATER_PK || (0, import_node_fs3.readFileSync)(privateKeyPath, "utf-8");
269
- const cert = process.env.UPDATER_CERT || (0, import_node_fs3.readFileSync)(certPath, "utf-8");
270
- writeCertToEntry(appEntryPath, cert);
446
+ const privateKey = process.env.UPDATER_PK || readFileSync3(privateKeyPath, "utf-8");
447
+ const cert = process.env.UPDATER_CERT || readFileSync3(certPath, "utf-8");
271
448
  return { privateKey, cert };
272
449
  }
273
450
  function parseSubjects(subject) {
@@ -275,12 +452,12 @@ function parseSubjects(subject) {
275
452
  }
276
453
 
277
454
  // src/build-plugins/option.ts
278
- function parseOptions(isBuild, pkg, options = {}) {
455
+ function parseOptions(pkg, sourcemap = false, minify = false, options = {}) {
279
456
  const {
280
457
  minimumVersion = "0.0.0",
281
458
  entry: {
282
- minify = isBuild,
283
- sourcemap = isBuild,
459
+ minify: entryMinify,
460
+ sourcemap: entrySourcemap,
284
461
  entryOutputDirPath = "dist-entry",
285
462
  appEntryPath = "electron/entry.ts",
286
463
  nativeModuleEntryMap = {},
@@ -318,8 +495,8 @@ function parseOptions(isBuild, pkg, options = {}) {
318
495
  rendererDistPath
319
496
  };
320
497
  const buildEntryOption = {
321
- minify,
322
- sourcemap,
498
+ minify: entryMinify ?? minify,
499
+ sourcemap: entrySourcemap ?? sourcemap,
323
500
  entryOutputDirPath,
324
501
  appEntryPath,
325
502
  nativeModuleEntryMap,
@@ -329,7 +506,6 @@ function parseOptions(isBuild, pkg, options = {}) {
329
506
  keyLength,
330
507
  privateKeyPath,
331
508
  certPath,
332
- appEntryPath,
333
509
  subject,
334
510
  days
335
511
  });
@@ -343,62 +519,235 @@ function parseOptions(isBuild, pkg, options = {}) {
343
519
  generateSignature,
344
520
  generateVersionJson
345
521
  };
346
- return { buildAsarOption, buildEntryOption, buildVersionOption, postBuild };
522
+ return { buildAsarOption, buildEntryOption, buildVersionOption, postBuild, cert };
523
+ }
524
+
525
+ // src/build-plugins/bytecode/index.ts
526
+ import path2 from "node:path";
527
+ import fs2 from "node:fs";
528
+ import { createFilter, normalizePath } from "vite";
529
+ import MagicString2 from "magic-string";
530
+ function bytecodePlugin(isBuild, env, options = {}) {
531
+ if (!isBuild) {
532
+ return null;
533
+ }
534
+ const {
535
+ protectedStrings = [],
536
+ enablePreload = false
537
+ } = options;
538
+ if (!enablePreload && env === "preload") {
539
+ bytecodeLog.warn('bytecodePlugin is skiped in preload. To enable in preload, please manually set the "enablePreload" option to true and set `sandbox: false` when creating the window', { timestamp: true });
540
+ return null;
541
+ }
542
+ const filter = createFilter(/\.(m?[jt]s|[jt]sx)$/);
543
+ let config;
544
+ let bytecodeRequired = false;
545
+ let bytecodeFiles = [];
546
+ return {
547
+ name: `${bytecodeId}-${env}`,
548
+ apply: "build",
549
+ enforce: "post",
550
+ configResolved(resolvedConfig) {
551
+ config = resolvedConfig;
552
+ },
553
+ transform(code, id2) {
554
+ if (protectedStrings.length === 0 || !filter(id2)) {
555
+ return;
556
+ }
557
+ return convertString(code, protectedStrings, !!config.build.sourcemap);
558
+ },
559
+ generateBundle(options2) {
560
+ if (options2.format !== "es" && bytecodeRequired) {
561
+ this.emitFile({
562
+ type: "asset",
563
+ source: bytecodeModuleLoaderCode + "\n",
564
+ name: "Bytecode Loader File",
565
+ fileName: bytecodeModuleLoader
566
+ });
567
+ }
568
+ },
569
+ renderChunk(code, chunk, options2) {
570
+ if (options2.format === "es") {
571
+ bytecodeLog.warn(
572
+ 'bytecodePlugin does not support ES module, please remove "type": "module" in package.json or set the "build.rollupOptions.output.format" option to "cjs".',
573
+ { timestamp: true }
574
+ );
575
+ return null;
576
+ }
577
+ if (chunk.type === "chunk") {
578
+ bytecodeRequired = true;
579
+ return convertArrowToFunction(code);
580
+ }
581
+ return null;
582
+ },
583
+ async writeBundle(options2, output) {
584
+ if (options2.format === "es" || !bytecodeRequired) {
585
+ return;
586
+ }
587
+ const outDir = options2.dir;
588
+ bytecodeFiles = [];
589
+ const bundles = Object.keys(output);
590
+ const chunks = Object.values(output).filter(
591
+ (chunk) => chunk.type === "chunk" && chunk.fileName !== bytecodeModuleLoader
592
+ );
593
+ const bytecodeChunks = chunks.map((chunk) => chunk.fileName);
594
+ const nonEntryChunks = chunks.filter((chunk) => !chunk.isEntry).map((chunk) => path2.basename(chunk.fileName));
595
+ const pattern = nonEntryChunks.map((chunk) => `(${chunk})`).join("|");
596
+ const bytecodeRE = pattern ? new RegExp(`require\\(\\S*(?=(${pattern})\\S*\\))`, "g") : null;
597
+ const getBytecodeLoaderBlock = (chunkFileName) => {
598
+ return `require("${toRelativePath(bytecodeModuleLoader, normalizePath(chunkFileName))}");`;
599
+ };
600
+ await Promise.all(
601
+ bundles.map(async (name) => {
602
+ const chunk = output[name];
603
+ if (chunk.type === "chunk") {
604
+ let _code = chunk.code;
605
+ if (bytecodeRE && _code.match(bytecodeRE)) {
606
+ let match;
607
+ const s = new MagicString2(_code);
608
+ while (match = bytecodeRE.exec(_code)) {
609
+ const [prefix, chunkName] = match;
610
+ const len = prefix.length + chunkName.length;
611
+ s.overwrite(match.index, match.index + len, prefix + chunkName + "c", {
612
+ contentOnly: true
613
+ });
614
+ }
615
+ _code = s.toString();
616
+ }
617
+ const chunkFilePath = path2.resolve(outDir, name);
618
+ if (bytecodeChunks.includes(name)) {
619
+ const bytecodeBuffer = await compileToBytecode(_code);
620
+ fs2.writeFileSync(path2.resolve(outDir, name + "c"), bytecodeBuffer);
621
+ if (chunk.isEntry) {
622
+ const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
623
+ const bytecodeModuleBlock = `require("./${path2.basename(name) + "c"}");`;
624
+ const code = `${useStrict}
625
+ ${bytecodeLoaderBlock}
626
+ module.exports=${bytecodeModuleBlock}
627
+ `;
628
+ fs2.writeFileSync(chunkFilePath, code);
629
+ } else {
630
+ fs2.unlinkSync(chunkFilePath);
631
+ }
632
+ bytecodeFiles.push({ name: name + "c", size: bytecodeBuffer.length });
633
+ } else {
634
+ if (chunk.isEntry) {
635
+ let hasBytecodeMoudle = false;
636
+ const idsToHandle = /* @__PURE__ */ new Set([...chunk.imports, ...chunk.dynamicImports]);
637
+ for (const moduleId of idsToHandle) {
638
+ if (bytecodeChunks.includes(moduleId)) {
639
+ hasBytecodeMoudle = true;
640
+ break;
641
+ }
642
+ const moduleInfo = this.getModuleInfo(moduleId);
643
+ if (moduleInfo && !moduleInfo.isExternal) {
644
+ const { importers, dynamicImporters } = moduleInfo;
645
+ for (const importerId of importers) {
646
+ idsToHandle.add(importerId);
647
+ }
648
+ for (const importerId of dynamicImporters) {
649
+ idsToHandle.add(importerId);
650
+ }
651
+ }
652
+ }
653
+ const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
654
+ _code = hasBytecodeMoudle ? _code.replace(useStrict, `${useStrict}
655
+ ${bytecodeLoaderBlock}`) : _code;
656
+ }
657
+ fs2.writeFileSync(chunkFilePath, _code);
658
+ }
659
+ }
660
+ })
661
+ );
662
+ },
663
+ closeBundle() {
664
+ const outDir = `${normalizePath(path2.relative(config.root, path2.resolve(config.root, config.build.outDir)))}/`;
665
+ bytecodeFiles.forEach((file) => {
666
+ const kbs = file.size / 1e3;
667
+ bytecodeLog.info(
668
+ `${outDir}${file.name} => ${kbs.toFixed(2)} kB`,
669
+ { timestamp: true }
670
+ );
671
+ });
672
+ bytecodeLog.info(`${bytecodeFiles.length} bundles compiled into bytecode.`, { timestamp: true });
673
+ bytecodeFiles = [];
674
+ }
675
+ };
347
676
  }
348
677
 
349
678
  // src/vite.ts
350
679
  function debugStartup(args) {
351
680
  process.env.VSCODE_DEBUG ? console.log("[startup] Electron App") : args.startup();
352
681
  }
353
- var id = "electron-incremental-updater";
354
- var log = (0, import_vite3.createLogger)("info", { prefix: `[${id}]` });
355
- function electronWithUpdater(options) {
356
- const {
682
+ async function electronWithUpdater(options) {
683
+ let {
357
684
  isBuild,
358
- pkg,
685
+ pkg = await loadPackageJSON(),
359
686
  main: _main,
360
687
  preload: _preload,
688
+ sourcemap = !isBuild,
689
+ minify = isBuild,
361
690
  updater,
691
+ bytecode,
362
692
  useNotBundle = true,
363
693
  logParsedOptions
364
694
  } = options;
365
- const _options = parseOptions(isBuild, pkg, updater);
695
+ if (!pkg) {
696
+ log.error(`package.json not found`, { timestamp: true });
697
+ return null;
698
+ }
699
+ if (!pkg.version || !pkg.name || !pkg.main) {
700
+ log.error(`package.json not valid`, { timestamp: true });
701
+ return null;
702
+ }
703
+ const _options = parseOptions(pkg, sourcemap, minify, updater);
704
+ const bytecodeOptions = typeof bytecode === "object" ? bytecode : bytecode === true ? { protectedStrings: [] } : void 0;
705
+ if (bytecodeOptions) {
706
+ minify = false;
707
+ }
366
708
  try {
367
- (0, import_node_fs4.rmSync)(_options.buildAsarOption.electronDistPath, { recursive: true, force: true });
368
- (0, import_node_fs4.rmSync)(_options.buildEntryOption.entryOutputDirPath, { recursive: true, force: true });
709
+ rmSync2(_options.buildAsarOption.electronDistPath, { recursive: true, force: true });
710
+ rmSync2(_options.buildEntryOption.entryOutputDirPath, { recursive: true, force: true });
369
711
  } catch (ignore) {
370
712
  }
371
713
  log.info(`remove old files`, { timestamp: true });
372
- const { buildAsarOption, buildEntryOption, buildVersionOption, postBuild } = _options;
714
+ const { buildAsarOption, buildEntryOption, buildVersionOption, postBuild, cert } = _options;
373
715
  const { entryOutputDirPath, nativeModuleEntryMap, appEntryPath } = buildEntryOption;
374
- const sourcemap = isBuild || !!process.env.VSCODE_DEBUG;
375
- const _appPath = (0, import_node_path3.join)(entryOutputDirPath, "entry.js");
376
- if ((0, import_node_path3.resolve)((0, import_vite3.normalizePath)(pkg.main)) !== (0, import_node_path3.resolve)((0, import_vite3.normalizePath)(_appPath))) {
377
- throw new Error(`wrong "main" field in package.json: "${pkg.main}", it should be "${(0, import_vite3.normalizePath)(_appPath)}"`);
716
+ sourcemap ??= isBuild || !!process.env.VSCODE_DEBUG;
717
+ const _appPath = normalizePath2(join2(entryOutputDirPath, "entry.js"));
718
+ if (resolve(normalizePath2(pkg.main)) !== resolve(_appPath)) {
719
+ throw new Error(`wrong "main" field in package.json: "${pkg.main}", it should be "${_appPath}"`);
378
720
  }
379
- let isInit = false;
380
721
  const _buildEntry = async () => {
381
- await buildEntry(buildEntryOption);
382
- log.info(`build entry to '${entryOutputDirPath}'`, { timestamp: true });
722
+ await buildEntry(buildEntryOption, cert, isBuild ? bytecodeOptions?.protectedStrings : void 0);
723
+ log.info(`vite build entry to '${entryOutputDirPath}'`, { timestamp: true });
383
724
  };
384
- const _postBuild = postBuild ? async () => postBuild({
725
+ const _postBuild = postBuild ? async () => await postBuild({
385
726
  getPathFromEntryOutputDir(...paths) {
386
- return (0, import_node_path3.join)(entryOutputDirPath, ...paths);
727
+ return join2(entryOutputDirPath, ...paths);
387
728
  },
388
- existsAndCopyToEntryOutputDir({ from, to, skipIfExist = true }) {
389
- if ((0, import_node_fs4.existsSync)(from)) {
390
- const target = (0, import_node_path3.join)(entryOutputDirPath, to ?? (0, import_node_path3.basename)(from));
391
- if (!skipIfExist || !(0, import_node_fs4.existsSync)(target)) {
729
+ copyToEntryOutputDir({ from, to, skipIfExist = true }) {
730
+ if (existsSync4(from)) {
731
+ const target = join2(entryOutputDirPath, to ?? basename2(from));
732
+ if (!skipIfExist || !existsSync4(target)) {
392
733
  try {
393
- (0, import_node_fs4.cpSync)(from, target);
394
- } catch (ignore) {
395
- log.warn(`copy failed: ${ignore}`);
734
+ cpSync(from, target);
735
+ } catch (error) {
736
+ log.warn(`copy failed: ${error}`);
396
737
  }
397
738
  }
398
739
  }
399
740
  }
400
741
  }) : async () => {
401
742
  };
743
+ let isInit = false;
744
+ const rollupOptions = {
745
+ // external: [
746
+ // /^node:/,
747
+ // ...Object.keys('dependencies' in pkg ? pkg.dependencies as object : {}),
748
+ // ],
749
+ external: (src) => src.startsWith("node:") || Object.keys("dependencies" in pkg ? pkg.dependencies : {}).includes(src)
750
+ };
402
751
  const electronPluginOptions = {
403
752
  main: {
404
753
  entry: _main.files,
@@ -410,16 +759,17 @@ function electronWithUpdater(options) {
410
759
  }
411
760
  _main.onstart ? _main.onstart(args) : args.startup();
412
761
  },
413
- vite: (0, import_vite3.mergeConfig)(
762
+ vite: mergeConfig2(
414
763
  {
415
- plugins: !isBuild && useNotBundle ? [(0, import_plugin.notBundle)()] : void 0,
764
+ plugins: [
765
+ !isBuild && useNotBundle ? notBundle() : void 0,
766
+ bytecodeOptions && bytecodePlugin(isBuild, "main", bytecodeOptions)
767
+ ],
416
768
  build: {
417
769
  sourcemap,
418
- minify: isBuild,
770
+ minify,
419
771
  outDir: `${buildAsarOption.electronDistPath}/main`,
420
- rollupOptions: {
421
- external: Object.keys("dependencies" in pkg ? pkg.dependencies : {})
422
- }
772
+ rollupOptions
423
773
  }
424
774
  },
425
775
  _main.vite ?? {}
@@ -428,9 +778,10 @@ function electronWithUpdater(options) {
428
778
  preload: {
429
779
  input: _preload.files,
430
780
  onstart: _preload.onstart,
431
- vite: (0, import_vite3.mergeConfig)(
781
+ vite: mergeConfig2(
432
782
  {
433
783
  plugins: [
784
+ bytecodeOptions && bytecodePlugin(isBuild, "preload", bytecodeOptions),
434
785
  {
435
786
  name: `${id}-build`,
436
787
  enforce: "post",
@@ -439,6 +790,7 @@ function electronWithUpdater(options) {
439
790
  },
440
791
  async closeBundle() {
441
792
  await _buildEntry();
793
+ await _postBuild();
442
794
  await buildAsar(buildAsarOption);
443
795
  log.info(`build asar to '${buildAsarOption.asarOutputPath}'`, { timestamp: true });
444
796
  await buildVersion(buildVersionOption);
@@ -448,11 +800,9 @@ function electronWithUpdater(options) {
448
800
  ],
449
801
  build: {
450
802
  sourcemap: sourcemap ? "inline" : void 0,
451
- minify: isBuild,
803
+ minify,
452
804
  outDir: `${buildAsarOption.electronDistPath}/preload`,
453
- rollupOptions: {
454
- external: Object.keys("dependencies" in pkg ? pkg.dependencies : {})
455
- }
805
+ rollupOptions
456
806
  }
457
807
  },
458
808
  _preload.vite ?? {}
@@ -465,14 +815,14 @@ function electronWithUpdater(options) {
465
815
  ...electronPluginOptions,
466
816
  updater: { buildAsarOption, buildEntryOption, buildVersionOption }
467
817
  },
468
- (key2, value) => key2 === "privateKey" || key2 === "cert" ? "***" : value,
818
+ (key, value) => (key === "privateKey" || key === "cert") && !(typeof logParsedOptions === "object" && logParsedOptions.showKeys === true) ? "***" : value,
469
819
  2
470
820
  ),
471
821
  { timestamp: true }
472
822
  );
473
823
  let extraHmrPlugin;
474
824
  if (nativeModuleEntryMap) {
475
- const files = [...Object.values(nativeModuleEntryMap), appEntryPath].map((file) => (0, import_node_path3.resolve)((0, import_vite3.normalizePath)(file)));
825
+ const files = [...Object.values(nativeModuleEntryMap), appEntryPath].map((file) => resolve(normalizePath2(file)));
476
826
  extraHmrPlugin = {
477
827
  name: `${id}-dev`,
478
828
  apply() {
@@ -482,19 +832,17 @@ function electronWithUpdater(options) {
482
832
  server.watcher.add(files).on(
483
833
  "change",
484
834
  (p) => files.includes(p) && _buildEntry().then(async () => {
485
- await import_vite_plugin_electron.startup.exit();
835
+ await startup.exit();
486
836
  await _postBuild();
487
- await (0, import_vite_plugin_electron.startup)();
837
+ await startup();
488
838
  })
489
839
  );
490
840
  }
491
841
  };
492
842
  }
493
- return [(0, import_simple.default)(electronPluginOptions), extraHmrPlugin];
843
+ return [ElectronSimple(electronPluginOptions), extraHmrPlugin];
494
844
  }
495
- // Annotate the CommonJS export names for ESM import in node:
496
- 0 && (module.exports = {
845
+ export {
497
846
  debugStartup,
498
- electronWithUpdater,
499
- log
500
- });
847
+ electronWithUpdater
848
+ };