electron-incremental-update 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -111
- 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 +156 -95
- package/dist/index.mjs +100 -44
- package/dist/noDep-TvZoKVF8.d.mts +31 -0
- package/dist/noDep-TvZoKVF8.d.ts +31 -0
- package/dist/utils.d.mts +91 -46
- package/dist/utils.d.ts +91 -46
- package/dist/utils.js +153 -99
- package/dist/utils.mjs +18 -20
- package/dist/vite.d.mts +208 -41
- package/dist/vite.d.ts +208 -41
- package/dist/vite.js +249 -124
- package/dist/vite.mjs +226 -100
- package/package.json +21 -10
- package/dist/chunk-6UZHBPFT.mjs +0 -113
- 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,134 @@
|
|
|
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
|
|
51
52
|
|
|
52
53
|
```ts
|
|
53
|
-
// electron/
|
|
54
|
-
import { initApp
|
|
55
|
-
import {
|
|
54
|
+
// electron/entry.ts
|
|
55
|
+
import { initApp } from 'electron-incremental-update'
|
|
56
|
+
import { parseGithubCdnURL } from 'electron-incremental-update/utils'
|
|
57
|
+
import { repository } from '../package.json'
|
|
56
58
|
|
|
57
59
|
const SIGNATURE_CERT = '' // auto generate certificate when start app
|
|
58
60
|
|
|
59
61
|
initApp({ onStart: console.log })
|
|
60
|
-
// can be updater option or function that return updater
|
|
61
62
|
.setUpdater({
|
|
62
63
|
SIGNATURE_CERT,
|
|
63
|
-
|
|
64
|
-
repository,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
receiveBeta: true
|
|
64
|
+
// repository,
|
|
65
|
+
// updateJsonURL: parseGithubCdnURL(repository, 'https://your.cdn.url/', 'version.json'),
|
|
66
|
+
// releaseAsarURL: parseGithubCdnURL(repository, 'https://your.cdn.url/', `download/latest/${name}.asar.gz`),
|
|
67
|
+
// receiveBeta: true
|
|
68
68
|
})
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
- [some
|
|
71
|
+
- [some CDN resources](https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34):
|
|
72
72
|
|
|
73
|
-
###
|
|
73
|
+
### Setup `vite.config.ts`
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
All options are documented with JSDoc
|
|
76
76
|
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
- privatekey is read from `process.env.UPDATER_PK` first, then read config
|
|
77
|
+
- cert will read from `process.env.UPDATER_CERT` first, if absend, read config
|
|
78
|
+
- privatekey will read from `process.env.UPDATER_PK` first, if absend, read config
|
|
80
79
|
|
|
81
80
|
```ts
|
|
82
|
-
// vite.config.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
// vite.config.mts
|
|
82
|
+
import { defineConfig } from 'vite'
|
|
83
|
+
import { debugStartup, electronWithUpdater } from 'electron-incremental-update/vite'
|
|
84
|
+
import pkg from './package.json'
|
|
86
85
|
|
|
86
|
+
export default defineConfig(async ({ command }) => {
|
|
87
|
+
const isBuild = command === 'build'
|
|
87
88
|
return {
|
|
88
89
|
plugins: [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
electronWithUpdater({
|
|
91
|
+
pkg,
|
|
92
|
+
isBuild,
|
|
93
|
+
logParsedOptions: true,
|
|
94
|
+
main: {
|
|
95
|
+
files: ['./electron/main/index.ts', './electron/main/worker.ts'],
|
|
96
|
+
// see https://github.com/electron-vite/electron-vite-vue/blob/85ed267c4851bf59f32888d766c0071661d4b94c/vite.config.ts#L22-L28
|
|
97
|
+
onstart: debugStartup,
|
|
93
98
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// ...
|
|
97
|
-
vite: {
|
|
98
|
-
plugins: [
|
|
99
|
-
updater({
|
|
100
|
-
productName: pkg.name,
|
|
101
|
-
version: pkg.version,
|
|
102
|
-
isBuild,
|
|
103
|
-
}),
|
|
104
|
-
],
|
|
105
|
-
// ...
|
|
106
|
-
}
|
|
99
|
+
preload: {
|
|
100
|
+
files: './electron/preload/index.ts',
|
|
107
101
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// ...
|
|
102
|
+
updater: {
|
|
103
|
+
// options
|
|
111
104
|
}
|
|
112
|
-
|
|
113
|
-
// ...
|
|
105
|
+
}),
|
|
114
106
|
],
|
|
115
|
-
|
|
107
|
+
server: process.env.VSCODE_DEBUG && (() => {
|
|
108
|
+
const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL)
|
|
109
|
+
return {
|
|
110
|
+
host: url.hostname,
|
|
111
|
+
port: +url.port,
|
|
112
|
+
}
|
|
113
|
+
})(),
|
|
116
114
|
}
|
|
117
115
|
})
|
|
118
116
|
```
|
|
119
117
|
|
|
120
|
-
###
|
|
118
|
+
### Modify package.json
|
|
121
119
|
|
|
122
120
|
```json
|
|
123
121
|
{
|
|
124
|
-
//
|
|
125
|
-
"main": "app.js" // <- app entry file path
|
|
122
|
+
"main": "dist-entry/entry.js" // <- entry file path
|
|
126
123
|
}
|
|
127
124
|
```
|
|
128
125
|
|
|
129
|
-
###
|
|
126
|
+
### Config electron-builder
|
|
130
127
|
|
|
131
128
|
```js
|
|
132
129
|
const { name } = require('./package.json')
|
|
133
130
|
|
|
134
|
-
const
|
|
131
|
+
const targetFile = `${name}.asar`
|
|
135
132
|
/**
|
|
136
133
|
* @type {import('electron-builder').Configuration}
|
|
137
134
|
*/
|
|
@@ -139,26 +136,21 @@ module.exports = {
|
|
|
139
136
|
appId: 'YourAppID',
|
|
140
137
|
productName: name,
|
|
141
138
|
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/**',
|
|
139
|
+
// entry files
|
|
140
|
+
'dist-entry',
|
|
150
141
|
],
|
|
142
|
+
npmRebuild: false,
|
|
151
143
|
asarUnpack: [
|
|
152
|
-
'**/*.{node,dll}',
|
|
144
|
+
'**/*.{node,dll,dylib,so}',
|
|
153
145
|
],
|
|
154
146
|
directories: {
|
|
155
147
|
output: 'release',
|
|
156
148
|
},
|
|
157
149
|
extraResources: [
|
|
158
|
-
{ from: `release/${
|
|
150
|
+
{ from: `release/${targetFile}`, to: targetFile }, // <- asar file
|
|
159
151
|
],
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
// disable publish
|
|
153
|
+
publish: null,
|
|
162
154
|
}
|
|
163
155
|
```
|
|
164
156
|
|
|
@@ -170,21 +162,23 @@ To use electron's `net` module for updating, the `checkUpdate` and `download` fu
|
|
|
170
162
|
|
|
171
163
|
However, you have the option to customize the download function when creating the updater.
|
|
172
164
|
|
|
173
|
-
**NOTE: There
|
|
165
|
+
**NOTE: There should only one function and should be default export in the entry file**
|
|
174
166
|
|
|
175
167
|
```ts
|
|
176
168
|
// electron/main/index.ts
|
|
177
|
-
import
|
|
178
|
-
import {
|
|
169
|
+
import { startupWithUpdater } from 'electron-incremental-update'
|
|
170
|
+
import { getPathFromAppNameAsar, getVersions } from 'electron-incremental-update/utils'
|
|
179
171
|
import { app } from 'electron'
|
|
180
|
-
import { name } from '../../package.json'
|
|
181
172
|
|
|
182
|
-
|
|
173
|
+
export default startupWithUpdater((updater) => {
|
|
183
174
|
await app.whenReady()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
175
|
+
|
|
176
|
+
const { appVersion, electronVersion, entryVersion } = getVersions()
|
|
177
|
+
console.log(`${app.name}.asar path`, getPathFromAppNameAsar())
|
|
178
|
+
console.log('app version:', appVersion)
|
|
179
|
+
console.log('entry (installer) version', entryVersion)
|
|
180
|
+
console.log('electron version', electronVersion)
|
|
181
|
+
|
|
188
182
|
updater.onDownloading = ({ percent }) => {
|
|
189
183
|
console.log(percent)
|
|
190
184
|
}
|
|
@@ -201,41 +195,95 @@ const startup: StartupWithUpdater = (updater: Updater) => {
|
|
|
201
195
|
buttons: ['Download', 'Later'],
|
|
202
196
|
message: 'Application update available!',
|
|
203
197
|
})
|
|
204
|
-
response
|
|
198
|
+
if (response !== 0) {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
const downloadResult = await updater.download()
|
|
202
|
+
if (downloadResult) {
|
|
203
|
+
updater.quitAndInstall()
|
|
204
|
+
}
|
|
205
205
|
}
|
|
206
206
|
})
|
|
207
|
-
}
|
|
208
|
-
export default startup
|
|
207
|
+
})
|
|
209
208
|
```
|
|
210
209
|
|
|
211
210
|
### use native modules
|
|
212
211
|
|
|
213
|
-
the native modules
|
|
212
|
+
All the **native modules** should be set as `dependency` in `package.json`. `electron-rebuild` only check dependencies inside `dependency` field.
|
|
214
213
|
|
|
215
|
-
to
|
|
214
|
+
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`
|
|
215
|
+
|
|
216
|
+
in `vite.config.ts`
|
|
216
217
|
|
|
217
218
|
```ts
|
|
218
|
-
|
|
219
|
-
|
|
219
|
+
const plugin = electronWithUpdater({
|
|
220
|
+
// options...
|
|
221
|
+
updater: {
|
|
222
|
+
entry: {
|
|
223
|
+
nativeModuleEntryMap: {
|
|
224
|
+
db: './electron/native/db.ts',
|
|
225
|
+
},
|
|
226
|
+
postBuild: async ({ existsAndCopyToEntryOutputDir }) => {
|
|
227
|
+
// for better-sqlite3
|
|
228
|
+
existsAndCopyToEntryOutputDir({
|
|
229
|
+
from: './node_modules/better-sqlite3/build/Release/better_sqlite3.node',
|
|
230
|
+
skipIfExist: false,
|
|
231
|
+
})
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
})
|
|
236
|
+
```
|
|
220
237
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
238
|
+
in `electron/native/db.ts`
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import Database from 'better-sqlite3'
|
|
242
|
+
import { getPaths } from 'electron-incremental-update/utils'
|
|
243
|
+
|
|
244
|
+
const db = new Database(':memory:', { nativeBinding: getPaths().getPathFromEntryAsar('better_sqlite3.node') })
|
|
245
|
+
|
|
246
|
+
export function test() {
|
|
247
|
+
db.exec(
|
|
248
|
+
'DROP TABLE IF EXISTS employees; '
|
|
228
249
|
+ 'CREATE TABLE IF NOT EXISTS employees (name TEXT, salary INTEGER)',
|
|
229
|
-
)
|
|
250
|
+
)
|
|
230
251
|
|
|
231
|
-
db.prepare('INSERT INTO employees VALUES (:n, :s)').run({
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
})
|
|
252
|
+
db.prepare('INSERT INTO employees VALUES (:n, :s)').run({
|
|
253
|
+
n: 'James',
|
|
254
|
+
s: 5000,
|
|
255
|
+
})
|
|
235
256
|
|
|
236
|
-
const r = db.prepare('SELECT * from employees').all()
|
|
237
|
-
console.log(r)
|
|
238
|
-
// [ { name: 'James', salary: 50000 } ]
|
|
257
|
+
const r = db.prepare('SELECT * from employees').all()
|
|
258
|
+
console.log(r)
|
|
259
|
+
// [ { name: 'James', salary: 50000 } ]
|
|
239
260
|
|
|
240
|
-
db.close()
|
|
261
|
+
db.close()
|
|
262
|
+
}
|
|
241
263
|
```
|
|
264
|
+
|
|
265
|
+
in `electron/main/service.ts`
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { loadNativeModuleFromEntry } from 'electron-incremental-update/utils'
|
|
269
|
+
|
|
270
|
+
const requireNative = loadNativeModuleFromEntry()
|
|
271
|
+
|
|
272
|
+
requireNative<typeof import('../native/db')>('db').test()
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
in `electron-builder.config.js`
|
|
276
|
+
|
|
277
|
+
```js
|
|
278
|
+
module.exports = {
|
|
279
|
+
files: [
|
|
280
|
+
'dist-entry',
|
|
281
|
+
// exclude better-sqlite3 from electron-builder
|
|
282
|
+
'!node_modules/better-sqlite3/**',
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
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
|
+
};
|