electron-incremental-update 0.9.1 → 1.0.1
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 +172 -112
- package/dist/{chunk-CMBFI77K.mjs → chunk-GB6VLKJZ.mjs} +48 -28
- package/dist/{chunk-5BZLJPHJ.mjs → chunk-GXZSAUBR.mjs} +1 -8
- package/dist/chunk-OUZLSVQC.mjs +148 -0
- package/dist/index.d.mts +102 -80
- package/dist/index.d.ts +102 -80
- package/dist/index.js +134 -71
- package/dist/index.mjs +97 -43
- package/dist/noDep-TvZoKVF8.d.mts +31 -0
- package/dist/noDep-TvZoKVF8.d.ts +31 -0
- package/dist/utils.d.mts +85 -48
- package/dist/utils.d.ts +85 -48
- package/dist/utils.js +127 -86
- package/dist/utils.mjs +14 -20
- package/dist/vite.d.mts +218 -41
- package/dist/vite.d.ts +218 -41
- package/dist/vite.js +245 -122
- package/dist/vite.mjs +222 -98
- package/package.json +18 -11
- package/dist/chunk-SPZL37O5.mjs +0 -124
- package/dist/updateJson-synsK-Pt.d.mts +0 -11
- package/dist/updateJson-synsK-Pt.d.ts +0 -11
package/README.md
CHANGED
|
@@ -1,137 +1,136 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Electron Incremental Updater
|
|
2
2
|
|
|
3
|
-
This project
|
|
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.
|
|
4
4
|
|
|
5
|
-
There will be two asar in production, `app.asar` and
|
|
5
|
+
There will be two asar in production, `app.asar` and `${name}.asar` (`electron.app.name`, also as the `name` field in `package.json`).
|
|
6
6
|
|
|
7
|
-
The `app.asar` is used to load
|
|
7
|
+
The `app.asar` is used to load `${name}.asar` and initialize the `Updater`.
|
|
8
8
|
|
|
9
|
-
The new
|
|
9
|
+
The new `${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 `${name}.asar` will be replaced by the new one. Hooks like `beforeDoUpdate` are provided.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
All **native modules** should be packaged into `app.asar` to reduce `${name}.asar` file size, [see usage](#use-native-modules)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
no `vite-plugin-electron-renderer` config
|
|
14
14
|
|
|
15
|
-
-
|
|
16
|
-
- **all options are documented in the jsdoc**
|
|
15
|
+
- inspired by [Obsidian](https://obsidian.md/)'s upgrade strategy
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## Install
|
|
19
18
|
|
|
20
19
|
### npm
|
|
21
20
|
```bash
|
|
22
|
-
npm install electron-incremental-update
|
|
21
|
+
npm install -D vite-plugin-electron electron-incremental-update
|
|
23
22
|
```
|
|
24
23
|
### yarn
|
|
25
24
|
```bash
|
|
26
|
-
yarn add electron-incremental-update
|
|
25
|
+
yarn add -D vite-plugin-electron electron-incremental-update
|
|
27
26
|
```
|
|
28
27
|
### pnpm
|
|
29
28
|
```bash
|
|
30
|
-
pnpm add electron-incremental-update
|
|
29
|
+
pnpm add -D vite-plugin-electron electron-incremental-update
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
##
|
|
32
|
+
## Getting started
|
|
33
|
+
|
|
34
|
+
### Project structure
|
|
34
35
|
|
|
35
36
|
base on [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
|
|
36
37
|
|
|
37
38
|
```
|
|
38
39
|
electron
|
|
39
|
-
├──
|
|
40
|
-
├── electron-env.d.ts
|
|
40
|
+
├── entry.ts // <- entry file
|
|
41
41
|
├── main
|
|
42
|
-
│
|
|
43
|
-
|
|
44
|
-
└──
|
|
42
|
+
│ └── index.ts
|
|
43
|
+
├── preload
|
|
44
|
+
│ └── index.ts
|
|
45
|
+
└── native // possible native modules
|
|
45
46
|
└── index.ts
|
|
46
47
|
src
|
|
47
48
|
└── ...
|
|
48
49
|
```
|
|
49
50
|
|
|
50
|
-
###
|
|
51
|
+
### Setup entry
|
|
52
|
+
|
|
53
|
+
in `electron/entry.ts` (build by `Esbuild`)
|
|
51
54
|
|
|
52
55
|
```ts
|
|
53
|
-
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
+
import { initApp } from 'electron-incremental-update'
|
|
57
|
+
import { parseGithubCdnURL } from 'electron-incremental-update/utils'
|
|
58
|
+
import { repository } from '../package.json'
|
|
56
59
|
|
|
57
60
|
const SIGNATURE_CERT = '' // auto generate certificate when start app
|
|
58
61
|
|
|
59
62
|
initApp({ onStart: console.log })
|
|
60
|
-
// can be updater option or function that return updater
|
|
61
63
|
.setUpdater({
|
|
62
64
|
SIGNATURE_CERT,
|
|
63
|
-
|
|
64
|
-
repository,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
receiveBeta: true
|
|
65
|
+
// repository,
|
|
66
|
+
// updateJsonURL: parseGithubCdnURL(repository, 'https://your.cdn.url/', 'version.json'),
|
|
67
|
+
// releaseAsarURL: parseGithubCdnURL(repository, 'https://your.cdn.url/', `download/latest/${name}.asar.gz`),
|
|
68
|
+
// receiveBeta: true
|
|
68
69
|
})
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
- [some
|
|
72
|
+
- [some CDN resources](https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34):
|
|
73
|
+
|
|
74
|
+
### Setup `vite.config.ts`
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
All options are documented with JSDoc
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
- cert will read from `process.env.UPDATER_CERT` first, if absend, read config
|
|
79
|
+
- privatekey will read from `process.env.UPDATER_PK` first, if absend, read config
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
- cert is read from `process.env.UPDATER_CERT` first, then read config
|
|
79
|
-
- privatekey is read from `process.env.UPDATER_PK` first, then read config
|
|
81
|
+
in `vite.config.mts`
|
|
80
82
|
|
|
81
83
|
```ts
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// ...
|
|
84
|
+
import { defineConfig } from 'vite'
|
|
85
|
+
import { debugStartup, electronWithUpdater } from 'electron-incremental-update/vite'
|
|
86
|
+
import pkg from './package.json'
|
|
86
87
|
|
|
88
|
+
export default defineConfig(async ({ command }) => {
|
|
89
|
+
const isBuild = command === 'build'
|
|
87
90
|
return {
|
|
88
91
|
plugins: [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
electronWithUpdater({
|
|
93
|
+
pkg,
|
|
94
|
+
isBuild,
|
|
95
|
+
logParsedOptions: true,
|
|
96
|
+
main: {
|
|
97
|
+
files: ['./electron/main/index.ts', './electron/main/worker.ts'],
|
|
98
|
+
// see https://github.com/electron-vite/electron-vite-vue/blob/85ed267c4851bf59f32888d766c0071661d4b94c/vite.config.ts#L22-L28
|
|
99
|
+
onstart: debugStartup,
|
|
93
100
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// ...
|
|
97
|
-
vite: {
|
|
98
|
-
plugins: [
|
|
99
|
-
updater({
|
|
100
|
-
productName: pkg.name,
|
|
101
|
-
version: pkg.version,
|
|
102
|
-
isBuild,
|
|
103
|
-
}),
|
|
104
|
-
],
|
|
105
|
-
// ...
|
|
106
|
-
}
|
|
101
|
+
preload: {
|
|
102
|
+
files: './electron/preload/index.ts',
|
|
107
103
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// ...
|
|
104
|
+
updater: {
|
|
105
|
+
// options
|
|
111
106
|
}
|
|
112
|
-
|
|
113
|
-
// ...
|
|
107
|
+
}),
|
|
114
108
|
],
|
|
115
|
-
|
|
109
|
+
server: process.env.VSCODE_DEBUG && (() => {
|
|
110
|
+
const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL)
|
|
111
|
+
return {
|
|
112
|
+
host: url.hostname,
|
|
113
|
+
port: +url.port,
|
|
114
|
+
}
|
|
115
|
+
})(),
|
|
116
116
|
}
|
|
117
117
|
})
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
###
|
|
120
|
+
### Modify package.json
|
|
121
121
|
|
|
122
122
|
```json
|
|
123
123
|
{
|
|
124
|
-
//
|
|
125
|
-
"main": "app.js" // <- app entry file path
|
|
124
|
+
"main": "dist-entry/entry.js" // <- entry file path
|
|
126
125
|
}
|
|
127
126
|
```
|
|
128
127
|
|
|
129
|
-
###
|
|
128
|
+
### Config electron-builder
|
|
130
129
|
|
|
131
130
|
```js
|
|
132
131
|
const { name } = require('./package.json')
|
|
133
132
|
|
|
134
|
-
const
|
|
133
|
+
const targetFile = `${name}.asar`
|
|
135
134
|
/**
|
|
136
135
|
* @type {import('electron-builder').Configuration}
|
|
137
136
|
*/
|
|
@@ -139,26 +138,21 @@ module.exports = {
|
|
|
139
138
|
appId: 'YourAppID',
|
|
140
139
|
productName: name,
|
|
141
140
|
files: [
|
|
142
|
-
|
|
143
|
-
'
|
|
144
|
-
'!**/{tsconfig.json,tsconfig.node.json,tsconfig.web.json}',
|
|
145
|
-
'!**/*debug*.*',
|
|
146
|
-
'!**/*.{md,zip,map}',
|
|
147
|
-
'!**/*.{c,cpp,h,hpp,cc,hh,cxx,hxx,gypi,gyp,sh}',
|
|
148
|
-
'!**/.{github,vscode}',
|
|
149
|
-
'!node_modules/**/better-sqlite3/deps/**',
|
|
141
|
+
// entry files
|
|
142
|
+
'dist-entry',
|
|
150
143
|
],
|
|
144
|
+
npmRebuild: false,
|
|
151
145
|
asarUnpack: [
|
|
152
|
-
'**/*.{node,dll}',
|
|
146
|
+
'**/*.{node,dll,dylib,so}',
|
|
153
147
|
],
|
|
154
148
|
directories: {
|
|
155
149
|
output: 'release',
|
|
156
150
|
},
|
|
157
151
|
extraResources: [
|
|
158
|
-
{ from: `release/${
|
|
152
|
+
{ from: `release/${targetFile}`, to: targetFile }, // <- asar file
|
|
159
153
|
],
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
// disable publish
|
|
155
|
+
publish: null,
|
|
162
156
|
}
|
|
163
157
|
```
|
|
164
158
|
|
|
@@ -170,21 +164,24 @@ To use electron's `net` module for updating, the `checkUpdate` and `download` fu
|
|
|
170
164
|
|
|
171
165
|
However, you have the option to customize the download function when creating the updater.
|
|
172
166
|
|
|
173
|
-
**NOTE: There
|
|
167
|
+
**NOTE: There should only one function and should be default export in the entry file**
|
|
168
|
+
|
|
169
|
+
in `electron/main/index.ts`
|
|
174
170
|
|
|
175
171
|
```ts
|
|
176
|
-
|
|
177
|
-
import
|
|
178
|
-
import { appInfo, getAppVersion, getElectronVersion, getProductAsarPath } from 'electron-incremental-update/utils'
|
|
172
|
+
import { startupWithUpdater } from 'electron-incremental-update'
|
|
173
|
+
import { getPathFromAppNameAsar, getVersions } from 'electron-incremental-update/utils'
|
|
179
174
|
import { app } from 'electron'
|
|
180
|
-
import { name } from '../../package.json'
|
|
181
175
|
|
|
182
|
-
|
|
176
|
+
export default startupWithUpdater((updater) => {
|
|
183
177
|
await app.whenReady()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
178
|
+
|
|
179
|
+
const { appVersion, electronVersion, entryVersion } = getVersions()
|
|
180
|
+
console.log(`${app.name}.asar path`, getPathFromAppNameAsar())
|
|
181
|
+
console.log('app version:', appVersion)
|
|
182
|
+
console.log('entry (installer) version', entryVersion)
|
|
183
|
+
console.log('electron version', electronVersion)
|
|
184
|
+
|
|
188
185
|
updater.onDownloading = ({ percent }) => {
|
|
189
186
|
console.log(percent)
|
|
190
187
|
}
|
|
@@ -201,41 +198,104 @@ const startup: StartupWithUpdater = (updater: Updater) => {
|
|
|
201
198
|
buttons: ['Download', 'Later'],
|
|
202
199
|
message: 'Application update available!',
|
|
203
200
|
})
|
|
204
|
-
response
|
|
201
|
+
if (response !== 0) {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
const downloadResult = await updater.download()
|
|
205
|
+
if (downloadResult) {
|
|
206
|
+
updater.quitAndInstall()
|
|
207
|
+
}
|
|
205
208
|
}
|
|
206
209
|
})
|
|
207
|
-
}
|
|
208
|
-
export default startup
|
|
210
|
+
})
|
|
209
211
|
```
|
|
210
212
|
|
|
211
213
|
### use native modules
|
|
212
214
|
|
|
213
|
-
the native modules
|
|
215
|
+
All the **native modules** should be set as `dependency` in `package.json`. `electron-rebuild` only check dependencies inside `dependency` field.
|
|
214
216
|
|
|
215
|
-
to
|
|
217
|
+
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. You can setup `nativeModuleEntryMap` option to prebundle all the native modules and skip bundled by `electron-builder`
|
|
218
|
+
|
|
219
|
+
in `vite.config.ts`
|
|
216
220
|
|
|
217
221
|
```ts
|
|
218
|
-
|
|
219
|
-
|
|
222
|
+
const plugin = electronWithUpdater({
|
|
223
|
+
// options...
|
|
224
|
+
updater: {
|
|
225
|
+
entry: {
|
|
226
|
+
nativeModuleEntryMap: {
|
|
227
|
+
db: './electron/native/db.ts',
|
|
228
|
+
},
|
|
229
|
+
postBuild: async ({ existsAndCopyToEntryOutputDir }) => {
|
|
230
|
+
// for better-sqlite3
|
|
231
|
+
existsAndCopyToEntryOutputDir({
|
|
232
|
+
from: './node_modules/better-sqlite3/build/Release/better_sqlite3.node',
|
|
233
|
+
skipIfExist: false,
|
|
234
|
+
})
|
|
235
|
+
// for @napi-rs/image
|
|
236
|
+
const startStr = '@napi-rs+image-'
|
|
237
|
+
const fileName = (await readdir('./node_modules/.pnpm')).filter(p => p.startsWith(startStr))[0]
|
|
238
|
+
const archName = fileName.substring(startStr.length).split('@')[0]
|
|
239
|
+
existsAndCopyToEntryOutputDir({
|
|
240
|
+
from: `./node_modules/.pnpm/${fileName}/node_modules/@napi-rs/image-${archName}/image.${archName}.node`,
|
|
241
|
+
})
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
```
|
|
220
247
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
248
|
+
in `electron/native/db.ts`
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
import Database from 'better-sqlite3'
|
|
252
|
+
import { getPaths } from 'electron-incremental-update/utils'
|
|
253
|
+
|
|
254
|
+
const db = new Database(':memory:', { nativeBinding: getPaths().getPathFromEntryAsar('better_sqlite3.node') })
|
|
255
|
+
|
|
256
|
+
export function test() {
|
|
257
|
+
db.exec(
|
|
258
|
+
'DROP TABLE IF EXISTS employees; '
|
|
228
259
|
+ 'CREATE TABLE IF NOT EXISTS employees (name TEXT, salary INTEGER)',
|
|
229
|
-
)
|
|
260
|
+
)
|
|
230
261
|
|
|
231
|
-
db.prepare('INSERT INTO employees VALUES (:n, :s)').run({
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
})
|
|
262
|
+
db.prepare('INSERT INTO employees VALUES (:n, :s)').run({
|
|
263
|
+
n: 'James',
|
|
264
|
+
s: 5000,
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const r = db.prepare('SELECT * from employees').all()
|
|
268
|
+
console.log(r)
|
|
269
|
+
// [ { name: 'James', salary: 50000 } ]
|
|
270
|
+
|
|
271
|
+
db.close()
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
in `electron/main/service.ts`
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { loadNativeModuleFromEntry } from 'electron-incremental-update/utils'
|
|
235
279
|
|
|
236
|
-
const
|
|
237
|
-
console.log(r)
|
|
238
|
-
// [ { name: 'James', salary: 50000 } ]
|
|
280
|
+
const requireNative = loadNativeModuleFromEntry()
|
|
239
281
|
|
|
240
|
-
db.
|
|
282
|
+
requireNative<typeof import('../native/db')>('db').test()
|
|
241
283
|
```
|
|
284
|
+
|
|
285
|
+
in `electron-builder.config.js`
|
|
286
|
+
|
|
287
|
+
```js
|
|
288
|
+
module.exports = {
|
|
289
|
+
files: [
|
|
290
|
+
'dist-entry',
|
|
291
|
+
// exclude better-sqlite3 from electron-builder
|
|
292
|
+
'!node_modules/better-sqlite3/**',
|
|
293
|
+
// exclude @napi-rs/image from electron-builder
|
|
294
|
+
'!node_modules/@napi-rs*/**',
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT
|
|
@@ -6,32 +6,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
// src/utils/version.ts
|
|
10
|
-
function parseVersion(version) {
|
|
11
|
-
const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\.-]+))?/i;
|
|
12
|
-
const match = semver.exec(version);
|
|
13
|
-
if (!match) {
|
|
14
|
-
throw new TypeError(`invalid version: ${version}`);
|
|
15
|
-
}
|
|
16
|
-
const [major, minor, patch] = match.slice(1, 4).map(Number);
|
|
17
|
-
const ret = {
|
|
18
|
-
major,
|
|
19
|
-
minor,
|
|
20
|
-
patch,
|
|
21
|
-
stage: "",
|
|
22
|
-
stageVersion: -1
|
|
23
|
-
};
|
|
24
|
-
if (match[4]) {
|
|
25
|
-
let [stage, _v] = match[4].split(".");
|
|
26
|
-
ret.stage = stage;
|
|
27
|
-
ret.stageVersion = Number(_v) || -1;
|
|
28
|
-
}
|
|
29
|
-
if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch) || Number.isNaN(ret.stageVersion)) {
|
|
30
|
-
throw new TypeError(`invalid version: ${version}`);
|
|
31
|
-
}
|
|
32
|
-
return ret;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
9
|
// src/utils/zip.ts
|
|
36
10
|
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
37
11
|
import { gunzip, gzip } from "node:zlib";
|
|
@@ -67,9 +41,55 @@ async function zipFile(filePath, targetFilePath = `${filePath}.gz`) {
|
|
|
67
41
|
});
|
|
68
42
|
}
|
|
69
43
|
|
|
44
|
+
// src/utils/noDep.ts
|
|
45
|
+
function parseGithubCdnURL(originRepoURL, cdnPrefix, relativeFilePath) {
|
|
46
|
+
if (!originRepoURL.startsWith("https://github.com/")) {
|
|
47
|
+
throw new Error("origin url must start with https://github.com/");
|
|
48
|
+
}
|
|
49
|
+
originRepoURL = originRepoURL.trim().replace(/\/?$/, "/").trim();
|
|
50
|
+
relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
|
|
51
|
+
cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
|
|
52
|
+
return originRepoURL.replace("github.com", cdnPrefix) + relativeFilePath;
|
|
53
|
+
}
|
|
54
|
+
function handleUnexpectedErrors(callback) {
|
|
55
|
+
process.on("uncaughtException", callback);
|
|
56
|
+
process.on("unhandledRejection", callback);
|
|
57
|
+
}
|
|
58
|
+
function parseVersion(version) {
|
|
59
|
+
const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9\.-]+))?/i;
|
|
60
|
+
const match = semver.exec(version);
|
|
61
|
+
if (!match) {
|
|
62
|
+
throw new TypeError(`invalid version: ${version}`);
|
|
63
|
+
}
|
|
64
|
+
const [major, minor, patch] = match.slice(1, 4).map(Number);
|
|
65
|
+
const ret = {
|
|
66
|
+
major,
|
|
67
|
+
minor,
|
|
68
|
+
patch,
|
|
69
|
+
stage: "",
|
|
70
|
+
stageVersion: -1
|
|
71
|
+
};
|
|
72
|
+
if (match[4]) {
|
|
73
|
+
let [stage, _v] = match[4].split(".");
|
|
74
|
+
ret.stage = stage;
|
|
75
|
+
ret.stageVersion = Number(_v) || -1;
|
|
76
|
+
}
|
|
77
|
+
if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch) || Number.isNaN(ret.stageVersion)) {
|
|
78
|
+
throw new TypeError(`invalid version: ${version}`);
|
|
79
|
+
}
|
|
80
|
+
return ret;
|
|
81
|
+
}
|
|
82
|
+
function isUpdateJSON(json) {
|
|
83
|
+
const is = (j) => !!(j && j.minimumVersion && j.signature && j.size && j.version);
|
|
84
|
+
return is(json) && is(json?.beta);
|
|
85
|
+
}
|
|
86
|
+
|
|
70
87
|
export {
|
|
71
88
|
__require,
|
|
72
|
-
parseVersion,
|
|
73
89
|
unzipFile,
|
|
74
|
-
zipFile
|
|
90
|
+
zipFile,
|
|
91
|
+
parseGithubCdnURL,
|
|
92
|
+
handleUnexpectedErrors,
|
|
93
|
+
parseVersion,
|
|
94
|
+
isUpdateJSON
|
|
75
95
|
};
|
|
@@ -30,14 +30,7 @@ var verify = (buffer, signature2, cert) => {
|
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
// src/updateJson.ts
|
|
34
|
-
function isUpdateJSON(json) {
|
|
35
|
-
const is = (j) => "signature" in j && "version" in j && "size" in j && "minimumVersion" in j;
|
|
36
|
-
return is(json) && "beta" in json && is(json.beta);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
33
|
export {
|
|
40
34
|
signature,
|
|
41
|
-
verify
|
|
42
|
-
isUpdateJSON
|
|
35
|
+
verify
|
|
43
36
|
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-GB6VLKJZ.mjs";
|
|
4
|
+
|
|
5
|
+
// src/utils/electron.ts
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
7
|
+
import { basename, dirname, join } from "node:path";
|
|
8
|
+
import { release } from "node:os";
|
|
9
|
+
import { app } from "electron";
|
|
10
|
+
var is = {
|
|
11
|
+
dev: !app.isPackaged,
|
|
12
|
+
win: process.platform === "win32",
|
|
13
|
+
mac: process.platform === "darwin",
|
|
14
|
+
linux: process.platform === "linux"
|
|
15
|
+
};
|
|
16
|
+
function getPathFromAppNameAsar(...path) {
|
|
17
|
+
return is.dev ? "DEV.asar" : join(dirname(app.getAppPath()), `${app.name}.asar`, ...path);
|
|
18
|
+
}
|
|
19
|
+
function getVersions() {
|
|
20
|
+
const platform = is.win ? "Windows" : is.mac ? "MacOS" : process.platform.toUpperCase();
|
|
21
|
+
return {
|
|
22
|
+
appVersion: is.dev ? app.getVersion() : readFileSync(getPathFromAppNameAsar("version"), "utf-8"),
|
|
23
|
+
entryVersion: app.getVersion(),
|
|
24
|
+
electronVersion: process.versions.electron,
|
|
25
|
+
nodeVersion: process.versions.node,
|
|
26
|
+
systemVersion: `${platform} ${release()}`
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function loadNativeModuleFromEntry(devEntryDirPath = "../../dist-entry", entryDirPath = join(app.getAppPath(), basename(devEntryDirPath))) {
|
|
30
|
+
const path = is.dev ? devEntryDirPath : entryDirPath;
|
|
31
|
+
return (moduleName) => {
|
|
32
|
+
try {
|
|
33
|
+
return __require(join(path, moduleName));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("fail to load module", error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function restartApp() {
|
|
40
|
+
app.relaunch();
|
|
41
|
+
app.quit();
|
|
42
|
+
}
|
|
43
|
+
function setAppUserModelId(id) {
|
|
44
|
+
app.setAppUserModelId(is.dev ? process.execPath : id ?? `org.${app.name}`);
|
|
45
|
+
}
|
|
46
|
+
function disableHWAccForWin7() {
|
|
47
|
+
if (release().startsWith("6.1")) {
|
|
48
|
+
app.disableHardwareAcceleration();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function singleInstance(window) {
|
|
52
|
+
const result = app.requestSingleInstanceLock();
|
|
53
|
+
result ? app.on("second-instance", () => {
|
|
54
|
+
if (window) {
|
|
55
|
+
window.show();
|
|
56
|
+
if (window.isMinimized()) {
|
|
57
|
+
window.restore();
|
|
58
|
+
}
|
|
59
|
+
window.focus();
|
|
60
|
+
}
|
|
61
|
+
}) : app.quit();
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function setPortableAppDataPath(dirName = "data") {
|
|
65
|
+
const portablePath = join(dirname(app.getPath("exe")), dirName);
|
|
66
|
+
if (!existsSync(portablePath)) {
|
|
67
|
+
mkdirSync(portablePath);
|
|
68
|
+
}
|
|
69
|
+
app.setPath("appData", portablePath);
|
|
70
|
+
}
|
|
71
|
+
function waitAppReady(timeout = 1e3) {
|
|
72
|
+
return app.isReady() ? Promise.resolve() : new Promise((resolve, reject) => {
|
|
73
|
+
const _ = setTimeout(() => {
|
|
74
|
+
reject(new Error("app is not ready"));
|
|
75
|
+
}, timeout);
|
|
76
|
+
app.whenReady().then(() => {
|
|
77
|
+
clearTimeout(_);
|
|
78
|
+
resolve();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function getPaths(entryDirName = "dist-entry") {
|
|
83
|
+
const root = join(__dirname, "..");
|
|
84
|
+
const mainDirPath = join(root, "main");
|
|
85
|
+
const preloadDirPath = join(root, "preload");
|
|
86
|
+
const rendererDirPath = join(root, "renderer");
|
|
87
|
+
const devServerURL = process.env.VITE_DEV_SERVER_URL;
|
|
88
|
+
const indexHTMLPath = join(rendererDirPath, "index.html");
|
|
89
|
+
const publicDirPath = devServerURL ? join(root, "../public") : rendererDirPath;
|
|
90
|
+
return {
|
|
91
|
+
/**
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* devServerURL && win.loadURL(devServerURL)
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
devServerURL,
|
|
98
|
+
/**
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* win.loadFile(indexHTMLPath)
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
indexHTMLPath,
|
|
105
|
+
/**
|
|
106
|
+
* get path inside entry asar
|
|
107
|
+
* @param paths joined path
|
|
108
|
+
*/
|
|
109
|
+
getPathFromEntryAsar(...paths) {
|
|
110
|
+
return join(app.getAppPath(), entryDirName, ...paths);
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* get path inside `${app.name}.asar/main`
|
|
114
|
+
* @param paths joined path
|
|
115
|
+
*/
|
|
116
|
+
getPathFromMain(...paths) {
|
|
117
|
+
return join(mainDirPath, ...paths);
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* get path inside `${app.name}.asar/preload`
|
|
121
|
+
* @param paths joined path
|
|
122
|
+
*/
|
|
123
|
+
getPathFromPreload(...paths) {
|
|
124
|
+
return join(preloadDirPath, ...paths);
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* get path inside public dir
|
|
128
|
+
* @param paths joined path
|
|
129
|
+
*/
|
|
130
|
+
getPathFromPublic(...paths) {
|
|
131
|
+
return join(publicDirPath, ...paths);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export {
|
|
137
|
+
is,
|
|
138
|
+
getPathFromAppNameAsar,
|
|
139
|
+
getVersions,
|
|
140
|
+
loadNativeModuleFromEntry,
|
|
141
|
+
restartApp,
|
|
142
|
+
setAppUserModelId,
|
|
143
|
+
disableHWAccForWin7,
|
|
144
|
+
singleInstance,
|
|
145
|
+
setPortableAppDataPath,
|
|
146
|
+
waitAppReady,
|
|
147
|
+
getPaths
|
|
148
|
+
};
|