electron-incremental-update 2.0.0-beta.8 → 2.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/README.md CHANGED
@@ -1,41 +1,45 @@
1
- ## Electron Incremental Updater
1
+ ## Electron Incremental Update
2
2
 
3
- This project is based on [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron), provide a plugin that build on top of `ElectronSimple`, an `Updater` class and some useful utils for Electron.
3
+ This project is built on top of [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron), offers a lightweight update solution for Electron applications without using native executables.
4
4
 
5
- There will be two asar in production, `app.asar` and `${electron.app.name}.asar` (also as the `name` field in `package.json`).
5
+ ### Key Features
6
6
 
7
- The `app.asar` is used to load `${electron.app.name}.asar` and initialize the `Updater`.
7
+ The solution includes a Vite plugin, a startup entry function, an `Updater` class, and a set of utilities for Electron.
8
8
 
9
- The new `${electron.app.name}.asar`, which can download from remote or load from buffer, will be verified by `Updater` using presigned RSA + Signature. While passing the check and restart, the old `${electron.app.name}.asar` will be replaced by the new one. Hooks like `beforeDoUpdate` are provided.
9
+ It use 2 asar file structure for updates:
10
10
 
11
- All **native modules** should be packaged into `app.asar` to reduce `${electron.app.name}.asar` file size, [see usage](#use-native-modules). Therefore, auto upgrade of portable app is possible.
11
+ - `app.asar`: The application entry, loads the `${electron.app.name}.asar` and initializes the updater on startup
12
+ - `${electron.app.name}.asar`: The package that contains main / preload / renderer process code
12
13
 
13
- Support bytecode protection, [see details](#bytecode-protection)
14
+ ### Update Steps
14
15
 
15
- No `vite-plugin-electron-renderer` config
16
+ 1. Check update from remote server
17
+ 2. If update available, download the update asar, verify by presigned RSA + Signature and write to disk
18
+ 3. Quit and restart the app
19
+ 4. Replace the old `${electron.app.name}.asar` on startup and load the new one
16
20
 
17
- - inspired by [Obsidian](https://obsidian.md/)'s upgrade strategy
21
+ ### Other Features
18
22
 
19
- ## Install
23
+ - Update size reduction: All **native modules** should be packaged into `app.asar` to reduce `${electron.app.name}.asar` file size, [see usage](#use-native-modules)
24
+ - Bytecode protection: Use V8 cache to protect source code, [see details](#bytecode-protection)
20
25
 
21
- ### npm
22
- ```bash
23
- npm install -D vite-plugin-electron electron-incremental-update
26
+ ## Getting Started
27
+
28
+ ### Install
29
+
30
+ ```sh
31
+ npm install -D electron-incremental-update
24
32
  ```
25
- ### yarn
26
- ```bash
27
- yarn add -D vite-plugin-electron electron-incremental-update
33
+ ```sh
34
+ yarn add -D electron-incremental-update
28
35
  ```
29
- ### pnpm
30
- ```bash
31
- pnpm add -D vite-plugin-electron electron-incremental-update
36
+ ```sh
37
+ pnpm add -D electron-incremental-update
32
38
  ```
33
39
 
34
- ## Getting started
35
-
36
- ### Project structure
40
+ ### Project Structure
37
41
 
38
- base on [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
42
+ Base on [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
39
43
 
40
44
  ```
41
45
  electron
@@ -50,37 +54,43 @@ src
50
54
  └── ...
51
55
  ```
52
56
 
53
- ### Setup entry
57
+ ### Setup Entry
54
58
 
55
- in `electron/entry.ts` (build by `Esbuild`)
59
+ The entry is used to load the application and initialize the `Updater`
60
+
61
+ `Updater` use the `provider` to check and download the update. The built-in `GithubProvider` is based on `BaseProvider`, which implements the `IProvider` interface (see [types](#provider)). And the `provider` is optional, you can setup later
62
+
63
+ in `electron/entry.ts`
56
64
 
57
65
  ```ts
58
- import { initApp } from 'electron-incremental-update'
59
- import { parseGithubCdnURL } from 'electron-incremental-update/utils'
60
- import { repository } from '../package.json'
66
+ import { createElectronApp } from 'electron-incremental-update'
67
+ import { GitHubProvider } from 'electron-incremental-update/provider'
61
68
 
62
- initApp({
63
- // can be updater option or function that return updater
69
+ createElectronApp({
64
70
  updater: {
65
- SIGNATURE_CERT: 'custom certificate',
66
- repository,
67
- updateJsonURL: parseGithubCdnURL(repository, jsonPrefix, 'version.json'),
68
- releaseAsarURL: parseGithubCdnURL(repository, asarPrefix, `download/latest/${app.name}.asar.gz`),
69
- receiveBeta: true,
71
+ // optinal, you can setup later
72
+ provider: new GitHubProvider({
73
+ username: 'yourname',
74
+ repo: 'electron',
75
+ }),
76
+ },
77
+ beforeStart(mainFilePath, logger) {
78
+ logger?.debug(mainFilePath)
70
79
  },
71
- onStart: console.log
72
80
  })
73
81
  ```
74
82
 
75
- - [some CDN resources](https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34):
83
+ - [some Github CDN resources](https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34)
76
84
 
77
85
  ### Setup `vite.config.ts`
78
86
 
79
- All options are documented with JSDoc
87
+ The plugin config, `main` and `preload` parts are reference from [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
80
88
 
81
89
  - certificate will read from `process.env.UPDATER_CERT` first, if absend, read config
82
90
  - privatekey will read from `process.env.UPDATER_PK` first, if absend, read config
83
91
 
92
+ See all config in [types](#plugin)
93
+
84
94
  in `vite.config.mts`
85
95
 
86
96
  ```ts
@@ -126,7 +136,7 @@ export default defineConfig(async ({ command }) => {
126
136
  }
127
137
  ```
128
138
 
129
- ### Config electron-builder
139
+ ### Config `electron-builder`
130
140
 
131
141
  ```js
132
142
  const { name } = require('./package.json')
@@ -159,24 +169,13 @@ module.exports = {
159
169
 
160
170
  ## Usage
161
171
 
162
- ### Use in main process
172
+ ### Use In Main Process
163
173
 
164
- To use electron's `net` module for updating, the `checkUpdate` and `download` functions must be called after the app is ready by default. You have the option to customize the download function when creating the updater.
174
+ In most cases, you should also setup the `UpdateProvider` before updating, unless you setup params when calling `checkUpdate` or `downloadUpdate`.
165
175
 
166
- **NOTE: There should only one function and should be default export in the entry file**
176
+ The update steps are similar to [electron-updater](https://github.com/electron-userland/electron-updater) and have same methods and events on `Updater`
167
177
 
168
- in `electron/entry.ts`
169
-
170
- ```ts
171
- initApp({
172
- updater: {
173
- overrideFunctions: {
174
- downloadJSON: (url: string, headers: Record<string, any>) => {}
175
- // ...
176
- }
177
- },
178
- })
179
- ```
178
+ **NOTE: There should only one function and should be default export in the main index file**
180
179
 
181
180
  in `electron/main/index.ts`
182
181
 
@@ -188,45 +187,56 @@ import { app } from 'electron'
188
187
  export default startupWithUpdater((updater) => {
189
188
  await app.whenReady()
190
189
 
191
- const { appVersion, electronVersion, entryVersion } = getVersions()
192
- console.log(`${app.name}.asar path`, getPathFromAppNameAsar())
193
- console.log('app version:', appVersion)
194
- console.log('entry (installer) version', entryVersion)
195
- console.log('electron version', electronVersion)
190
+ console.table({
191
+ [`${app.name}.asar path:`]: getPathFromAppNameAsar(),
192
+ 'app version:': getAppVersion(),
193
+ 'entry (installer) version:': getEntryVersion(),
194
+ 'electron version:': process.versions.electron,
195
+ })
196
196
 
197
197
  updater.onDownloading = ({ percent }) => {
198
198
  console.log(percent)
199
199
  }
200
200
  updater.logger = console
201
201
  updater.receiveBeta = true
202
+ // setup provider later
203
+ updater.provider = new GitHubProvider({
204
+ user: 'yourname',
205
+ repo: 'electron',
206
+ // setup url handler
207
+ urlHandler: (url) => {
208
+ url.hostname = 'mirror.ghproxy.com'
209
+ url.pathname = `https://github.com${url.pathname}`
210
+ return url
211
+ }
212
+ })
202
213
 
203
- updater.checkUpdate().then(async (result) => {
204
- if (result === undefined) {
205
- console.log('Update Unavailable')
206
- } else if (result instanceof UpdaterError) {
207
- console.error(result)
208
- } else {
209
- console.log('new version: ', result.version)
210
- const { response } = await dialog.showMessageBox({
211
- type: 'info',
212
- buttons: ['Download', 'Later'],
213
- message: 'Application update available!',
214
- })
215
- if (response !== 0) {
216
- return
217
- }
218
- const downloadResult = await updater.download()
219
- if (downloadResult) {
220
- updater.quitAndInstall()
221
- }
214
+ updater.on('update-available', async ({ version }) => {
215
+ const { response } = await dialog.showMessageBox({
216
+ type: 'info',
217
+ buttons: ['Download', 'Later'],
218
+ message: `v${version} update available!`,
219
+ })
220
+ if (response !== 0) {
221
+ return
222
222
  }
223
+ await updater.downloadUpdate()
224
+ })
225
+ updater.on('update-not-available', (reason, info) => console.log(reason, info))
226
+ updater.on('download-progress', (data) => {
227
+ console.log(data)
228
+ main.send(BrowserWindow.getAllWindows()[0], 'msg', data)
229
+ })
230
+ updater.on('update-downloaded', () => {
231
+ updater.quitAndInstall()
223
232
  })
233
+ updater.checkForUpdates()
224
234
  })
225
235
  ```
226
236
 
227
- ### Use native modules
237
+ ### Use Native Modules
228
238
 
229
- All the **native modules** should be set as `dependency` in `package.json`. `electron-rebuild` only check dependencies inside `dependency` field.
239
+ To reduce production size, it is recommended that all the **native modules** should be set as `dependency` in `package.json` and other packages should be set as `devDependencies`. Also, `electron-rebuild` only check dependencies inside `dependency` field.
230
240
 
231
241
  If you are using `electron-builder` to build distributions, all the native modules with its **large relavent `node_modiles`** will be packaged into `app.asar` by default.
232
242
 
@@ -235,7 +245,7 @@ Luckily, `Esbuild` can bundle all the dependencies. Just follow the steps:
235
245
  1. setup `nativeModuleEntryMap` option
236
246
  2. Manually copy the native binaries in `postBuild` callback
237
247
  3. Exclude all the dependencies in `electron-builder`'s config
238
- 4. call the native functions with `loadNativeModuleFromEntry` in your code
248
+ 4. call the native functions with `requireNative` in your code
239
249
 
240
250
  #### Example
241
251
 
@@ -298,9 +308,7 @@ export function test(): void {
298
308
  in `electron/main/service.ts`
299
309
 
300
310
  ```ts
301
- import { loadNativeModuleFromEntry } from 'electron-incremental-update/utils'
302
-
303
- const requireNative = loadNativeModuleFromEntry()
311
+ import { requireNative } from 'electron-incremental-update/utils'
304
312
 
305
313
  requireNative<typeof import('../native/db')>('db').test()
306
314
  ```
@@ -311,131 +319,201 @@ in `electron-builder.config.js`
311
319
  module.exports = {
312
320
  files: [
313
321
  'dist-entry',
314
- // exclude dependencies in electron-builder config
322
+ // exclude all dependencies in electron-builder config
315
323
  '!node_modules/**',
316
324
  ]
317
325
  }
318
326
  ```
319
327
 
320
- ### Bytecode protection
321
-
322
- From v1.2, the vite plugin is able to generate bytecode to protect your application.
323
-
324
- It will automatically protect your `SIGNATURE_CERT` by default.
328
+ ### Bytecode Protection
325
329
 
326
- credit to [electron-vite](https://github.com/alex8088/electron-vite/blob/master/src/plugins/bytecode.ts), and improve the string protection (see [original issue](https://github.com/alex8088/electron-vite/issues/552))
330
+ Use V8 cache to protect the source code
327
331
 
328
332
  ```ts
329
333
  electronWithUpdater({
330
334
  // ...
331
- bytecode: true,
335
+ bytecode: true, // or options
332
336
  })
333
337
  ```
334
338
 
339
+ #### Benifits
340
+
341
+ https://electron-vite.org/guide/source-code-protection
342
+
343
+ - Improve the string protection (see [original issue](https://github.com/alex8088/electron-vite/issues/552)) and protect all strings by default
344
+ - Minification is allowed
345
+
335
346
  #### Limitation
336
347
 
337
- - only support commonjs
338
- - only for main process by default, if you want to use in preload script, please use `electronWithUpdater({ bytecode: { enablePreload: true } })` and set `sandbox: false` when creating window
348
+ - Only support commonjs
349
+ - Only for main process by default, if you want to use in preload script, please use `electronWithUpdater({ bytecode: { enablePreload: true } })` and set `sandbox: false` when creating window
339
350
 
340
351
  ### Types
341
352
 
342
- #### Updater
353
+ #### Entry
343
354
 
344
355
  ```ts
345
- export interface UpdaterOption {
356
+ export interface AppOption {
346
357
  /**
347
- * public key of signature, which will be auto generated by plugin,
348
- * generate by `selfsigned` if not set
358
+ * Path to index file that make {@link startupWithUpdater} as default export
359
+ *
360
+ * Generate from plugin configuration by default
349
361
  */
350
- SIGNATURE_CERT?: string
362
+ mainPath?: string
351
363
  /**
352
- * repository url, e.g. `https://github.com/electron/electron`
353
- *
354
- * you can use the `repository` in `package.json`
355
- *
356
- * if `updateJsonURL` or `releaseAsarURL` are absent,
357
- * `repository` will be used to determine the url
364
+ * Updater options
358
365
  */
359
- repository?: string
366
+ updater?: (() => Promisable<Updater>) | UpdaterOption
360
367
  /**
361
- * URL of version info json
362
- * @default `${repository.replace('github.com', 'raw.githubusercontent.com')}/master/version.json`
363
- * @throws if `updateJsonURL` and `repository` are all not set
368
+ * Hooks on rename temp asar path to `${app.name}.asar`
364
369
  */
365
- updateJsonURL?: string
370
+ onInstall?: OnInstallFunction
366
371
  /**
367
- * URL of release asar.gz
368
- * @default `${repository}/releases/download/v${version}/${app.name}-${version}.asar.gz`
369
- * @throws if `releaseAsarURL` and `repository` are all not set
372
+ * Hooks before app startup
373
+ * @param mainFilePath main file path of `${app.name}.asar`
374
+ * @param logger logger
370
375
  */
371
- releaseAsarURL?: string
376
+ beforeStart?: (mainFilePath: string, logger?: Logger) => Promisable<void>
372
377
  /**
373
- * whether to receive beta update
378
+ * Hooks on app startup error
379
+ * @param err installing or startup error
380
+ * @param logger logger
381
+ */
382
+ onStartError?: (err: unknown, logger?: Logger) => void
383
+ }
384
+ /**
385
+ * Hooks on rename temp asar path to `${app.name}.asar`
386
+ * @param install `() => renameSync(tempAsarPath, appNameAsarPath)`
387
+ * @param tempAsarPath temp(updated) asar path
388
+ * @param appNameAsarPath `${app.name}.asar` path
389
+ * @param logger logger
390
+ * @default install(); logger.info('update success!')
391
+ */
392
+ type OnInstallFunction = (
393
+ install: VoidFunction,
394
+ tempAsarPath: string,
395
+ appNameAsarPath: string,
396
+ logger?: Logger
397
+ ) => Promisable<void>
398
+ ```
399
+
400
+ #### Updater
401
+
402
+ ```ts
403
+ export interface UpdaterOption {
404
+ /**
405
+ * Update provider
406
+ *
407
+ * If you will not setup `UpdateJSON` or `Buffer` in params when checking update or download, this option is **required**
408
+ */
409
+ provider?: IProvider
410
+ /**
411
+ * Certifaction key of signature, which will be auto generated by plugin,
412
+ * generate by `selfsigned` if not set
413
+ */
414
+ SIGNATURE_CERT?: string
415
+ /**
416
+ * Whether to receive beta update
374
417
  */
375
418
  receiveBeta?: boolean
376
- overrideFunctions?: UpdaterOverrideFunctions
377
- downloadConfig?: UpdaterDownloadConfig
419
+ /**
420
+ * Updater logger
421
+ */
422
+ logger?: Logger
378
423
  }
424
+
379
425
  export type Logger = {
380
426
  info: (msg: string) => void
381
427
  debug: (msg: string) => void
382
428
  warn: (msg: string) => void
383
429
  error: (msg: string, e?: Error) => void
384
430
  }
431
+ ```
432
+ #### Provider
433
+
434
+ ```ts
435
+ export type OnDownloading = (progress: DownloadingInfo) => void
385
436
 
386
- export type UpdaterOverrideFunctions = {
437
+ export interface DownloadingInfo {
387
438
  /**
388
- * custom version compare function
389
- * @param version1 old version string
390
- * @param version2 new version string
391
- * @returns if version1 < version2
439
+ * Download buffer delta
392
440
  */
393
- isLowerVersion?: (version1: string, version2: string) => boolean | Promise<boolean>
441
+ delta: number
394
442
  /**
395
- * custom verify signature function
396
- * @param buffer file buffer
397
- * @param signature signature
398
- * @param cert certificate
399
- * @returns if signature is valid, returns the version or `true` , otherwise returns `false`
443
+ * Downloaded percent, 0 ~ 100
444
+ *
445
+ * If no `Content-Length` header, will be -1
446
+ */
447
+ percent: number
448
+ /**
449
+ * Total size
450
+ *
451
+ * If not `Content-Length` header, will be -1
400
452
  */
401
- verifySignaure?: (buffer: Buffer, signature: string, cert: string) => string | false | Promise<string | false>
453
+ total: number
402
454
  /**
403
- * custom download JSON function
404
- * @param url download url
405
- * @param header download header
406
- * @returns `UpdateJSON`
455
+ * Downloaded size
407
456
  */
408
- downloadJSON?: (url: string, headers: Record<string, any>) => Promise<UpdateJSON>
457
+ transferred: number
409
458
  /**
410
- * custom download buffer function
411
- * @param url download url
412
- * @param headers download header
413
- * @param total precaculated file total size
414
- * @param onDownloading on downloading callback
415
- * @returns `Buffer`
459
+ * Download speed, bytes per second
416
460
  */
417
- downloadBuffer?: (url: string, headers: Record<string, any>, total: number, onDownloading?: (progress: DownloadingInfo) => void) => Promise<Buffer>
461
+ bps: number
418
462
  }
419
463
 
420
- export type UpdaterDownloadConfig = {
464
+ export interface IProvider {
421
465
  /**
422
- * download user agent
423
- * @default 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'
466
+ * Provider name
424
467
  */
425
- userAgent?: string
468
+ name: string
426
469
  /**
427
- * extra download header, `accept` and `user-agent` is set by default
470
+ * Download update json
471
+ * @param versionPath parsed version path in project
472
+ * @param signal abort signal
428
473
  */
429
- extraHeader?: Record<string, string>
474
+ downloadJSON: (versionPath: string, signal: AbortSignal) => Promise<UpdateJSON>
475
+ /**
476
+ * Download update asar
477
+ * @param name app name
478
+ * @param updateInfo existing update info
479
+ * @param signal abort signal
480
+ * @param onDownloading hook for on downloading
481
+ */
482
+ downloadAsar: (
483
+ name: string,
484
+ updateInfo: UpdateInfo,
485
+ signal: AbortSignal,
486
+ onDownloading?: (info: DownloadingInfo) => void
487
+ ) => Promise<Buffer>
488
+ /**
489
+ * Check the old version is less than new version
490
+ * @param oldVer old version string
491
+ * @param newVer new version string
492
+ */
493
+ isLowerVersion: (oldVer: string, newVer: string) => boolean
494
+ /**
495
+ * Function to decompress file using brotli
496
+ * @param buffer compressed file buffer
497
+ */
498
+ unzipFile: (buffer: Buffer) => Promise<Buffer>
499
+ /**
500
+ * Verify asar signature,
501
+ * if signature is valid, returns the version, otherwise returns `undefined`
502
+ * @param buffer file buffer
503
+ * @param version target version
504
+ * @param signature signature
505
+ * @param cert certificate
506
+ */
507
+ verifySignaure: (buffer: Buffer, version: string, signature: string, cert: string) => Promisable<boolean>
430
508
  }
431
509
  ```
432
510
 
433
511
  #### Plugin
434
512
 
435
513
  ```ts
436
- type ElectronWithUpdaterOptions = {
514
+ export interface ElectronWithUpdaterOptions {
437
515
  /**
438
- * whether is in build mode
516
+ * Whether is in build mode
439
517
  * ```ts
440
518
  * export default defineConfig(({ command }) => {
441
519
  * const isBuild = command === 'build'
@@ -444,65 +522,77 @@ type ElectronWithUpdaterOptions = {
444
522
  */
445
523
  isBuild: boolean
446
524
  /**
447
- * manually setup package.json, read name, version and main
525
+ * Manually setup package.json, read name, version and main,
526
+ * use `local-pkg` of `loadPackageJSON()` to load package.json by default
448
527
  * ```ts
449
528
  * import pkg from './package.json'
450
529
  * ```
451
530
  */
452
531
  pkg?: PKG
453
532
  /**
454
- * whether to generate sourcemap
533
+ * Whether to generate sourcemap
534
+ * @default !isBuild
455
535
  */
456
536
  sourcemap?: boolean
457
537
  /**
458
- * whether to minify the code
538
+ * Whether to minify the code
539
+ * @default isBuild
459
540
  */
460
541
  minify?: boolean
461
542
  /**
462
- * whether to generate bytecode
543
+ * Whether to generate bytecode
463
544
  *
464
- * **only support commonjs**
545
+ * **Only support CommonJS**
465
546
  *
466
- * only main process by default, if you want to use in preload script, please use `electronWithUpdater({ bytecode: { enablePreload: true } })` and set `sandbox: false` when creating window
547
+ * Only main process by default, if you want to use in preload script, please use `electronWithUpdater({ bytecode: { enablePreload: true } })` and set `sandbox: false` when creating window
467
548
  */
468
549
  bytecode?: boolean | BytecodeOptions
469
550
  /**
470
- * use NotBundle() plugin in main
551
+ * Use `NotBundle()` plugin in main
471
552
  * @default true
472
553
  */
473
554
  useNotBundle?: boolean
555
+ /**
556
+ * Whether to generate version json
557
+ * @default isCI
558
+ */
559
+ buildVersionJson?: boolean
474
560
  /**
475
561
  * Whether to log parsed options
476
562
  *
477
- * to show certificate and private keys, set `logParsedOptions: { showKeys: true }`
563
+ * To show certificate and private keys, set `logParsedOptions: { showKeys: true }`
478
564
  */
479
565
  logParsedOptions?: boolean | { showKeys: boolean }
480
566
  /**
481
- * main options
567
+ * Main process options
568
+ *
569
+ * To change output directories, use `options.updater.paths.electronDistPath` instead
482
570
  */
483
- main: MakeRequiredAndReplaceKey<ElectronSimpleOptions['main'], 'entry', 'files'>
571
+ main: MakeRequiredAndReplaceKey<ElectronSimpleOptions['main'], 'entry', 'files'> & ExcludeOutputDirOptions
484
572
  /**
485
- * preload options
573
+ * Preload process options
574
+ *
575
+ * To change output directories, use `options.updater.paths.electronDistPath` instead
486
576
  */
487
- preload: MakeRequiredAndReplaceKey<Exclude<ElectronSimpleOptions['preload'], undefined>, 'input', 'files'>
577
+ preload: MakeRequiredAndReplaceKey<Exclude<ElectronSimpleOptions['preload'], undefined>, 'input', 'files'> & ExcludeOutputDirOptions
488
578
  /**
489
- * updater options
579
+ * Updater options
490
580
  */
491
581
  updater?: ElectronUpdaterOptions
492
582
  }
493
583
 
494
- type ElectronUpdaterOptions = {
584
+ export interface ElectronUpdaterOptions {
495
585
  /**
496
- * mini version of entry
586
+ * Minimum version of entry
497
587
  * @default '0.0.0'
498
588
  */
499
589
  minimumVersion?: string
500
590
  /**
501
- * config for entry (app.asar)
591
+ * Options for entry (app.asar)
502
592
  */
503
593
  entry?: BuildEntryOption
504
594
  /**
505
- * paths config
595
+ * Options for paths
506
596
  */
507
597
  paths?: {
508
598
  /**
@@ -536,23 +626,23 @@ type ElectronUpdaterOptions = {
536
626
  */
537
627
  keys?: {
538
628
  /**
539
- * path to the pem file that contains private key
540
- * if not ended with .pem, it will be appended
629
+ * Path to the pem file that contains private key
630
+ * If not ended with .pem, it will be appended
541
631
  *
542
- * **if `UPDATER_PK` is set, will read it instead of read from `privateKeyPath`**
632
+ * **If `UPDATER_PK` is set, will read it instead of read from `privateKeyPath`**
543
633
  * @default 'keys/private.pem'
544
634
  */
545
635
  privateKeyPath?: string
546
636
  /**
547
- * path to the pem file that contains public key
548
- * if not ended with .pem, it will be appended
637
+ * Path to the pem file that contains public key
638
+ * If not ended with .pem, it will be appended
549
639
  *
550
- * **if `UPDATER_CERT` is set, will read it instead of read from `certPath`**
640
+ * **If `UPDATER_CERT` is set, will read it instead of read from `certPath`**
551
641
  * @default 'keys/cert.pem'
552
642
  */
553
643
  certPath?: string
554
644
  /**
555
- * length of the key
645
+ * Length of the key
556
646
  * @default 2048
557
647
  */
558
648
  keyLength?: number
@@ -563,45 +653,44 @@ type ElectronUpdaterOptions = {
563
653
  */
564
654
  certInfo?: {
565
655
  /**
566
- * the subject of the certificate
656
+ * The subject of the certificate
567
657
  *
568
658
  * @default { commonName: `${app.name}`, organizationName: `org.${app.name}` }
569
659
  */
570
660
  subject?: DistinguishedName
571
661
  /**
572
- * expire days of the certificate
662
+ * Expire days of the certificate
573
663
  *
574
664
  * @default 3650
575
665
  */
576
666
  days?: number
577
667
  }
578
- overrideGenerator?: GeneratorOverrideFunctions
579
668
  }
669
+ overrideGenerator?: GeneratorOverrideFunctions
580
670
  }
581
671
 
582
- type BuildEntryOption = {
672
+ export interface BuildEntryOption {
583
673
  /**
584
- * whether to minify
674
+ * Override to minify on entry
585
675
  * @default isBuild
586
676
  */
587
677
  minify?: boolean
588
678
  /**
589
- * whether to generate sourcemap
590
- * @default isBuild
679
+ * Override to generate sourcemap on entry
591
680
  */
592
681
  sourcemap?: boolean
593
682
  /**
594
- * path to app entry output file
683
+ * Path to app entry output file
595
684
  * @default 'dist-entry'
596
685
  */
597
686
  entryOutputDirPath?: string
598
687
  /**
599
- * path to app entry file
688
+ * Path to app entry file
600
689
  * @default 'electron/entry.ts'
601
690
  */
602
691
  appEntryPath?: string
603
692
  /**
604
- * esbuild path map of native modules in entry directory
693
+ * Esbuild path map of native modules in entry directory
605
694
  *
606
695
  * @default {}
607
696
  * @example
@@ -609,7 +698,7 @@ type BuildEntryOption = {
609
698
  */
610
699
  nativeModuleEntryMap?: Record<string, string>
611
700
  /**
612
- * override options for esbuild
701
+ * Custom options for esbuild
613
702
  * ```ts
614
703
  * // default options
615
704
  * const options = {
@@ -628,34 +717,32 @@ type BuildEntryOption = {
628
717
  * loader: {
629
718
  * '.node': 'empty',
630
719
  * },
631
- * define: {
632
- * __SIGNATURE_CERT__: JSON.stringify(cert),
633
- * },
720
+ * define,
634
721
  * }
635
722
  * ```
636
723
  */
637
724
  overrideEsbuildOptions?: BuildOptions
638
725
  /**
639
- * resolve extra files on startup, such as `.node`
726
+ * Resolve extra files on startup, such as `.node`
640
727
  * @remark won't trigger will reload
641
728
  */
642
729
  postBuild?: (args: {
643
730
  /**
644
- * get path from `entryOutputDirPath`
731
+ * Get path from `entryOutputDirPath`
645
732
  */
646
733
  getPathFromEntryOutputDir: (...paths: string[]) => string
647
734
  /**
648
- * check exist and copy file to `entryOutputDirPath`
735
+ * Check exist and copy file to `entryOutputDirPath`
649
736
  *
650
- * if `to` absent, set to `basename(from)`
737
+ * If `to` absent, set to `basename(from)`
651
738
  *
652
- * if `skipIfExist` absent, skip copy if `to` exist
739
+ * If `skipIfExist` absent, skip copy if `to` exist
653
740
  */
654
741
  copyToEntryOutputDir: (options: {
655
742
  from: string
656
743
  to?: string
657
744
  /**
658
- * skip copy if `to` exist
745
+ * Skip copy if `to` exist
659
746
  * @default true
660
747
  */
661
748
  skipIfExist?: boolean
@@ -663,17 +750,22 @@ type BuildEntryOption = {
663
750
  }) => Promisable<void>
664
751
  }
665
752
 
666
- type GeneratorOverrideFunctions = {
753
+ export interface GeneratorOverrideFunctions {
667
754
  /**
668
- * custom signature generate function
755
+ * Custom signature generate function
669
756
  * @param buffer file buffer
670
757
  * @param privateKey private key
671
758
  * @param cert certificate string, **EOL must be '\n'**
672
759
  * @param version current version
673
760
  */
674
- generateSignature?: (buffer: Buffer, privateKey: string, cert: string, version: string) => string | Promise<string>
761
+ generateSignature?: (
762
+ buffer: Buffer,
763
+ privateKey: string,
764
+ cert: string,
765
+ version: string
766
+ ) => Promisable<string>
675
767
  /**
676
- * custom generate version json function
768
+ * Custom generate version json function
677
769
  * @param existingJson The existing JSON object.
678
770
  * @param buffer file buffer
679
771
  * @param signature generated signature
@@ -681,10 +773,27 @@ type GeneratorOverrideFunctions = {
681
773
  * @param minVersion The minimum version
682
774
  * @returns The updated version json
683
775
  */
684
- generateVersionJson?: (existingJson: UpdateJSON, buffer: Buffer, signature: string, version: string, minVersion: string) => UpdateJSON | Promise<UpdateJSON>
776
+ generateVersionJson?: (
777
+ existingJson: UpdateJSON,
778
+ signature: string,
779
+ version: string,
780
+ minVersion: string
781
+ ) => Promisable<UpdateJSON>
782
+ /**
783
+ * Custom generate zip file buffer
784
+ * @param buffer source buffer
785
+ */
786
+ generateGzipFile?: (buffer: Buffer) => Promisable<Buffer>
685
787
  }
686
788
  ```
687
789
 
790
+ ## Credits
791
+
792
+ - [Obsidian](https://obsidian.md/) for upgrade strategy
793
+ - [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron) for vite plugin
794
+ - [electron-builder](https://github.com/electron-userland/electron-builder) for update api
795
+ - [electron-vite](https://github.com/alex8088/electron-vite) for bytecode plugin inspiration
796
+
688
797
  ## License
689
798
 
690
799
  MIT