electron-incremental-update 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +299 -0
- package/dist/chunk-AKU6F3WT.mjs +11 -0
- package/dist/index.cjs +228 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.mjs +191 -0
- package/dist/vite.cjs +223 -0
- package/dist/vite.d.ts +74 -0
- package/dist/vite.mjs +194 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 subframe7536
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
## electron incremental updater
|
|
2
|
+
|
|
3
|
+
inspired by Obsidian's update strategy, using RSA + Signature to sign the update asar and replace the old one when verified
|
|
4
|
+
|
|
5
|
+
develop with [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron), and may be effect in other electron vite frameworks
|
|
6
|
+
|
|
7
|
+
### install
|
|
8
|
+
|
|
9
|
+
#### npm
|
|
10
|
+
```bash
|
|
11
|
+
npm install electron-incremental-update
|
|
12
|
+
```
|
|
13
|
+
#### yarn
|
|
14
|
+
```bash
|
|
15
|
+
yarn add electron-incremental-update
|
|
16
|
+
```
|
|
17
|
+
#### pnpm
|
|
18
|
+
```bash
|
|
19
|
+
pnpm add electron-incremental-update
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### usage
|
|
23
|
+
|
|
24
|
+
base on [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
electron
|
|
28
|
+
├── app.ts // <- add app entry file
|
|
29
|
+
├── electron-env.d.ts
|
|
30
|
+
├── main
|
|
31
|
+
│ ├── db.ts
|
|
32
|
+
│ ├── index.ts
|
|
33
|
+
└── preload
|
|
34
|
+
└── index.ts
|
|
35
|
+
src
|
|
36
|
+
└── ...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### setup app
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// electron/app.ts
|
|
43
|
+
import { createUpdater, initApp } from 'electron-incremental-update'
|
|
44
|
+
import { name, repository } from '../package.json'
|
|
45
|
+
|
|
46
|
+
const SIGNATURE_PUB = '' // auto generate RSA public key when start app
|
|
47
|
+
|
|
48
|
+
const updater = createUpdater({
|
|
49
|
+
SIGNATURE_PUB,
|
|
50
|
+
githubRepository: repository,
|
|
51
|
+
productName: name,
|
|
52
|
+
})
|
|
53
|
+
initApp(name, updater)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### setup main
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// electron/main/index.ts
|
|
60
|
+
import type { Updater } from 'electron-incremental-update'
|
|
61
|
+
import { getAppAsarPath, getAppVersion, getElectronVersion } from 'electron-incremental-update'
|
|
62
|
+
import { app } from 'electron'
|
|
63
|
+
import { name } from '../../package.json'
|
|
64
|
+
|
|
65
|
+
export default function (updater: Updater) {
|
|
66
|
+
console.log('\ncurrent:')
|
|
67
|
+
console.log(`\telectron: ${getElectronVersion()}`)
|
|
68
|
+
console.log(`\tasar path: ${getAppAsarPath(name)}`)
|
|
69
|
+
console.log(`\tapp: ${getAppVersion(name)}`)
|
|
70
|
+
|
|
71
|
+
updater.checkUpdate()
|
|
72
|
+
updater.on('checkResult', async (result, err) => {
|
|
73
|
+
switch (result) {
|
|
74
|
+
case 'success':
|
|
75
|
+
await dialog.showMessageBox({
|
|
76
|
+
type: 'info',
|
|
77
|
+
buttons: ['Restart', 'Later'],
|
|
78
|
+
message: 'Application successfully updated!',
|
|
79
|
+
}).then(({ response }) => {
|
|
80
|
+
if (response === 0) {
|
|
81
|
+
app.relaunch()
|
|
82
|
+
app.quit()
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
break
|
|
86
|
+
case 'unavailable':
|
|
87
|
+
console.log('Update Unavailable')
|
|
88
|
+
break
|
|
89
|
+
case 'fail':
|
|
90
|
+
console.error(err)
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
updater.on('downloadStart', console.log)
|
|
95
|
+
updater.on('downloading', console.log)
|
|
96
|
+
updater.on('downloadEnd', console.log)
|
|
97
|
+
updater.on('donwnloadError', console.error)
|
|
98
|
+
|
|
99
|
+
// app logics
|
|
100
|
+
app.whenReady().then(() => {
|
|
101
|
+
// ...
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### use native modules
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// db.ts
|
|
110
|
+
import { requireNative } from 'electron-incremental-update'
|
|
111
|
+
|
|
112
|
+
const Database = requireNative<typeof import('better-sqlite3')>('better-sqlite3')
|
|
113
|
+
const db = new Database(':memory:')
|
|
114
|
+
db.exec(
|
|
115
|
+
'DROP TABLE IF EXISTS employees; '
|
|
116
|
+
+ 'CREATE TABLE IF NOT EXISTS employees (name TEXT, salary INTEGER)',
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
db.prepare('INSERT INTO employees VALUES (:n, :s)').run({
|
|
120
|
+
n: 'James',
|
|
121
|
+
s: 50000,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const r = db.prepare('SELECT * from employees').all()
|
|
125
|
+
console.log(r)
|
|
126
|
+
// [ { name: 'James', salary: 50000 } ]
|
|
127
|
+
|
|
128
|
+
db.close()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### setup vite.config.ts
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { rmSync } from 'node:fs'
|
|
135
|
+
import { defineConfig } from 'vite'
|
|
136
|
+
import electron from 'vite-plugin-electron'
|
|
137
|
+
import updater from 'electron-incremental-update/vite'
|
|
138
|
+
import pkg from './package.json'
|
|
139
|
+
|
|
140
|
+
// https://vitejs.dev/config/
|
|
141
|
+
|
|
142
|
+
export default defineConfig(({ command }) => {
|
|
143
|
+
rmSync('dist-electron', { recursive: true, force: true })
|
|
144
|
+
|
|
145
|
+
const isServe = command === 'serve'
|
|
146
|
+
const isBuild = command === 'build'
|
|
147
|
+
const sourcemap = isServe || !!process.env.VSCODE_DEBUG
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
plugins: [
|
|
151
|
+
electron([
|
|
152
|
+
{
|
|
153
|
+
// Main-Process entry file of the Electron App.
|
|
154
|
+
entry: ['electron/main/index.ts'],
|
|
155
|
+
onstart(options) {
|
|
156
|
+
if (process.env.VSCODE_DEBUG) {
|
|
157
|
+
console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App')
|
|
158
|
+
} else {
|
|
159
|
+
options.startup()
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
vite: {
|
|
163
|
+
plugins: [
|
|
164
|
+
updater({ // options see below
|
|
165
|
+
productName: pkg.name,
|
|
166
|
+
version: pkg.version,
|
|
167
|
+
isBuild,
|
|
168
|
+
}),
|
|
169
|
+
],
|
|
170
|
+
build: {
|
|
171
|
+
sourcemap,
|
|
172
|
+
minify: false,
|
|
173
|
+
outDir: 'dist-electron/main',
|
|
174
|
+
rollupOptions: {
|
|
175
|
+
external: Object.keys('dependencies' in pkg ? pkg.dependencies : {}),
|
|
176
|
+
treeshake: true,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
// ...preload
|
|
183
|
+
},
|
|
184
|
+
]),
|
|
185
|
+
// ... other plugins
|
|
186
|
+
],
|
|
187
|
+
// ... other config
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
##### option
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
type Options = {
|
|
196
|
+
/**
|
|
197
|
+
* whether is in build mode
|
|
198
|
+
*/
|
|
199
|
+
isBuild: boolean
|
|
200
|
+
/**
|
|
201
|
+
* the name of you application
|
|
202
|
+
*
|
|
203
|
+
* you can set as 'name' in package.json
|
|
204
|
+
*/
|
|
205
|
+
productName: string
|
|
206
|
+
/**
|
|
207
|
+
* the version of you application
|
|
208
|
+
*
|
|
209
|
+
* you can set as 'version' in package.json
|
|
210
|
+
*/
|
|
211
|
+
version: string
|
|
212
|
+
/**
|
|
213
|
+
* Whether to minify
|
|
214
|
+
*/
|
|
215
|
+
minify?: boolean
|
|
216
|
+
paths?: {
|
|
217
|
+
/**
|
|
218
|
+
* Path to app entry file
|
|
219
|
+
* @default 'electron/app.ts'
|
|
220
|
+
*/
|
|
221
|
+
entryPath?: string
|
|
222
|
+
/**
|
|
223
|
+
* Path to app entry output file
|
|
224
|
+
* @default 'app.js'
|
|
225
|
+
*/
|
|
226
|
+
entryOutputPath?: string
|
|
227
|
+
/**
|
|
228
|
+
* Path to app entry file
|
|
229
|
+
* @default `release/${ProductName}.asar`
|
|
230
|
+
*/
|
|
231
|
+
asarOutputPath?: string
|
|
232
|
+
/**
|
|
233
|
+
* Path to electron build output
|
|
234
|
+
* @default `dist-electron`
|
|
235
|
+
*/
|
|
236
|
+
electronDistPath?: string
|
|
237
|
+
/**
|
|
238
|
+
* Path to renderer build output
|
|
239
|
+
* @default `dist`
|
|
240
|
+
*/
|
|
241
|
+
rendererDistPath?: string
|
|
242
|
+
}
|
|
243
|
+
keys?: {
|
|
244
|
+
/**
|
|
245
|
+
* Path to the pem file that contains private key
|
|
246
|
+
* if not ended with .pem, it will be appended
|
|
247
|
+
* @default 'public/private.pem'
|
|
248
|
+
*/
|
|
249
|
+
privateKeyPath?: string
|
|
250
|
+
/**
|
|
251
|
+
* Path to the pem file that contains public key
|
|
252
|
+
* if not ended with .pem, it will be appended
|
|
253
|
+
* @default 'public/public.pem'
|
|
254
|
+
*/
|
|
255
|
+
publicKeyPath?: string
|
|
256
|
+
/**
|
|
257
|
+
* Length of the key
|
|
258
|
+
* @default 2048
|
|
259
|
+
*/
|
|
260
|
+
keyLength?: number
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### electron-builder config
|
|
266
|
+
|
|
267
|
+
```js
|
|
268
|
+
const { name } = require('./package.json')
|
|
269
|
+
|
|
270
|
+
const target = `${name}.asar`
|
|
271
|
+
/**
|
|
272
|
+
* @type {import('electron-builder').Configuration}
|
|
273
|
+
*/
|
|
274
|
+
module.exports = {
|
|
275
|
+
appId: 'YourAppID',
|
|
276
|
+
productName: name,
|
|
277
|
+
files: [
|
|
278
|
+
'app.js', // <- app entry file
|
|
279
|
+
'!**/{.eslintignore,.eslintrc.cjs,.editorconfig,.prettierignore,.prettierrc.yaml,dev-app-update.yml,LICENSE,.nvmrc,.npmrc}',
|
|
280
|
+
'!**/{tsconfig.json,tsconfig.node.json,tsconfig.web.json}',
|
|
281
|
+
'!**/*debug*.*',
|
|
282
|
+
'!**/*.{md,zip,map}',
|
|
283
|
+
'!**/*.{c,cpp,h,hpp,cc,hh,cxx,hxx,gypi,gyp,sh}',
|
|
284
|
+
'!**/.{github,vscode}',
|
|
285
|
+
'!node_modules/**/better-sqlite3/deps/**',
|
|
286
|
+
],
|
|
287
|
+
asarUnpack: [
|
|
288
|
+
'**/*.{node,dll}',
|
|
289
|
+
],
|
|
290
|
+
directories: {
|
|
291
|
+
output: 'release',
|
|
292
|
+
},
|
|
293
|
+
extraResources: [
|
|
294
|
+
{ from: `release/${target}`, to: target }, // <- asar file
|
|
295
|
+
],
|
|
296
|
+
publish: null,
|
|
297
|
+
// ...
|
|
298
|
+
}
|
|
299
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
6
|
+
throw new Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
__require
|
|
11
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
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 key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || 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
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
createUpdater: () => createUpdater,
|
|
34
|
+
getAppAsarPath: () => getAppAsarPath,
|
|
35
|
+
getAppVersion: () => getAppVersion,
|
|
36
|
+
getElectronVersion: () => getElectronVersion,
|
|
37
|
+
getReleaseDnsPrefix: () => getReleaseDnsPrefix,
|
|
38
|
+
initApp: () => initApp,
|
|
39
|
+
requireNative: () => requireNative
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(src_exports);
|
|
42
|
+
var import_node_path2 = require("path");
|
|
43
|
+
var import_electron3 = require("electron");
|
|
44
|
+
|
|
45
|
+
// src/utils.ts
|
|
46
|
+
var import_node_fs = require("fs");
|
|
47
|
+
var import_node_path = require("path");
|
|
48
|
+
var import_electron = require("electron");
|
|
49
|
+
function getAppAsarPath(name) {
|
|
50
|
+
return import_electron.app.isPackaged ? (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${name}.asar`) : "dev";
|
|
51
|
+
}
|
|
52
|
+
function getElectronVersion() {
|
|
53
|
+
return import_electron.app.getVersion();
|
|
54
|
+
}
|
|
55
|
+
function getAppVersion(name) {
|
|
56
|
+
return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getAppAsarPath(name), "version"), "utf-8").trim() : getElectronVersion();
|
|
57
|
+
}
|
|
58
|
+
function requireNative(packageName) {
|
|
59
|
+
const path = import_electron.app.isPackaged ? (0, import_node_path.join)(import_electron.app.getAppPath(), "node_modules", packageName) : packageName;
|
|
60
|
+
return require(path);
|
|
61
|
+
}
|
|
62
|
+
function getReleaseDnsPrefix() {
|
|
63
|
+
const hub = "https://github.com";
|
|
64
|
+
return [
|
|
65
|
+
{ urlPrefix: `https://gh.gh2233.ml/${hub}`, maintainer: "@X.I.U/XIU2" },
|
|
66
|
+
{ urlPrefix: `https://ghproxy.com/${hub}`, maintainer: "gh-proxy" },
|
|
67
|
+
{ urlPrefix: `https://gh.ddlc.top/${hub}`, maintainer: "@mtr-static-official" },
|
|
68
|
+
{ urlPrefix: `https://ghdl.feizhuqwq.cf/${hub}`, maintainer: "feizhuqwq.com" },
|
|
69
|
+
{ urlPrefix: `https://slink.ltd/${hub}`, maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
70
|
+
{ urlPrefix: `https://git.xfj0.cn/${hub}`, maintainer: "anonymous1" },
|
|
71
|
+
{ urlPrefix: `https://gh.con.sh/${hub}`, maintainer: "anonymous2" },
|
|
72
|
+
{ urlPrefix: `https://ghps.cc/${hub}`, maintainer: "anonymous3" },
|
|
73
|
+
{ urlPrefix: "https://cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
74
|
+
{ urlPrefix: `https://hub.gitmirror.com/${hub}`, maintainer: "GitMirror" },
|
|
75
|
+
{ urlPrefix: `https://js.xxooo.ml/${hub}`, maintainer: "\u996D\u592A\u786C" },
|
|
76
|
+
{ urlPrefix: `https://proxy.freecdn.ml/?url=${hub}`, maintainer: "anonymous4" },
|
|
77
|
+
{ urlPrefix: "https://download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
78
|
+
{ urlPrefix: "https://download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
79
|
+
{ urlPrefix: "https://download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/updater.ts
|
|
84
|
+
var import_node_events = require("events");
|
|
85
|
+
var import_node_buffer = require("buffer");
|
|
86
|
+
var import_node_crypto = require("crypto");
|
|
87
|
+
var import_node_zlib = require("zlib");
|
|
88
|
+
var import_node_fs2 = require("fs");
|
|
89
|
+
var import_promises = require("fs/promises");
|
|
90
|
+
var import_node_https = __toESM(require("https"), 1);
|
|
91
|
+
var import_electron2 = require("electron");
|
|
92
|
+
function createUpdater({
|
|
93
|
+
SIGNATURE_PUB,
|
|
94
|
+
githubRepository: repository,
|
|
95
|
+
productName,
|
|
96
|
+
releaseCdnPrefix
|
|
97
|
+
}) {
|
|
98
|
+
const updater = new import_node_events.EventEmitter();
|
|
99
|
+
async function download(url, format) {
|
|
100
|
+
const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
101
|
+
return await new Promise((resolve2, reject) => {
|
|
102
|
+
import_node_https.default.get(url, (res) => {
|
|
103
|
+
if (format === "json") {
|
|
104
|
+
let data = "";
|
|
105
|
+
res.setEncoding("utf8");
|
|
106
|
+
res.headers = {
|
|
107
|
+
Accept: "application/json",
|
|
108
|
+
UserAgent: ua
|
|
109
|
+
};
|
|
110
|
+
res.on("data", (chunk) => data += chunk);
|
|
111
|
+
res.on("end", () => {
|
|
112
|
+
resolve2(JSON.parse(data));
|
|
113
|
+
});
|
|
114
|
+
} else if (format === "buffer") {
|
|
115
|
+
let data = [];
|
|
116
|
+
res.headers = {
|
|
117
|
+
Accept: "application/octet-stream",
|
|
118
|
+
UserAgent: ua
|
|
119
|
+
};
|
|
120
|
+
res.on("data", (chunk) => {
|
|
121
|
+
updater.emit("downloading", chunk.length);
|
|
122
|
+
data.push(chunk);
|
|
123
|
+
});
|
|
124
|
+
res.on("end", () => {
|
|
125
|
+
updater.emit("downloadEnd", true);
|
|
126
|
+
resolve2(import_node_buffer.Buffer.concat(data));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}).on("error", (e) => {
|
|
130
|
+
e && updater.emit("donwnloadError", e);
|
|
131
|
+
reject(e);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function extractFile(gzipFilePath) {
|
|
136
|
+
if (!gzipFilePath.endsWith(".asar.gz") || !(0, import_node_fs2.existsSync)(gzipFilePath)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
gzipFilePath = gzipFilePath.replace(".asar.gz", ".tmp.gz");
|
|
140
|
+
return new Promise((resolve2, reject) => {
|
|
141
|
+
const gunzip = (0, import_node_zlib.createGunzip)();
|
|
142
|
+
const input = (0, import_node_fs2.createReadStream)(gzipFilePath);
|
|
143
|
+
const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
|
|
144
|
+
const output = (0, import_node_fs2.createWriteStream)(outputFilePath);
|
|
145
|
+
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
146
|
+
await (0, import_promises.rm)(gzipFilePath);
|
|
147
|
+
resolve2(outputFilePath);
|
|
148
|
+
}).on("error", async (err) => {
|
|
149
|
+
await (0, import_promises.rm)(gzipFilePath);
|
|
150
|
+
output.destroy(err);
|
|
151
|
+
reject(err);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function verify(buffer, signature) {
|
|
156
|
+
return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature, "base64");
|
|
157
|
+
}
|
|
158
|
+
function needUpdate(version) {
|
|
159
|
+
const parseVersion = (version2) => {
|
|
160
|
+
const [major, minor, patch] = version2.split(".");
|
|
161
|
+
return ~~major * 100 + ~~minor * 10 + ~~patch;
|
|
162
|
+
};
|
|
163
|
+
return import_electron2.app.isPackaged && parseVersion(import_electron2.app.getVersion()) < parseVersion(version);
|
|
164
|
+
}
|
|
165
|
+
async function checkUpdate(releaseCdnPrefix2) {
|
|
166
|
+
const gzipPath = `../${productName}.asar.gz`;
|
|
167
|
+
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
168
|
+
const base = repository.replace("https://github.com", "");
|
|
169
|
+
const updateJSONUrl = `https://cdn.jsdelivr.net/gh/${base}/version.json`;
|
|
170
|
+
const downloadUrl = `${releaseCdnPrefix2 ? `${releaseCdnPrefix2}/${base}` : repository}/releases/download/latest/${productName}.asar.gz`;
|
|
171
|
+
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
172
|
+
await (0, import_promises.rm)(tmpFile);
|
|
173
|
+
}
|
|
174
|
+
const json = await download(updateJSONUrl, "json");
|
|
175
|
+
if (!json) {
|
|
176
|
+
throw new Error("fetch update json failed");
|
|
177
|
+
}
|
|
178
|
+
const {
|
|
179
|
+
signature,
|
|
180
|
+
version,
|
|
181
|
+
size
|
|
182
|
+
} = json;
|
|
183
|
+
console.log(version, size, signature);
|
|
184
|
+
if (!needUpdate(version)) {
|
|
185
|
+
return "unavailable";
|
|
186
|
+
}
|
|
187
|
+
updater.emit("downloadStart", size);
|
|
188
|
+
const buffer = await download(downloadUrl, "buffer");
|
|
189
|
+
if (!verify(buffer, signature)) {
|
|
190
|
+
throw new Error("file broken, invalid signature!");
|
|
191
|
+
}
|
|
192
|
+
await (0, import_promises.writeFile)(gzipPath, buffer);
|
|
193
|
+
await extractFile(gzipPath);
|
|
194
|
+
return "success";
|
|
195
|
+
}
|
|
196
|
+
const onCheck = async () => {
|
|
197
|
+
try {
|
|
198
|
+
const result = await checkUpdate(releaseCdnPrefix);
|
|
199
|
+
updater.emit("checkResult", result);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
updater.emit("checkResult", "fail", error);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
updater.on("check", onCheck);
|
|
205
|
+
updater.checkUpdate = onCheck;
|
|
206
|
+
return updater;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/index.ts
|
|
210
|
+
function initApp(productName, updater, option) {
|
|
211
|
+
const {
|
|
212
|
+
electronDistPath = "dist-electron",
|
|
213
|
+
mainPath = "main/index.js"
|
|
214
|
+
} = option ?? {};
|
|
215
|
+
const mainDir = import_electron3.app.isPackaged ? `../${productName}.asar` : electronDistPath;
|
|
216
|
+
const entry = (0, import_node_path2.resolve)(__dirname, mainDir, mainPath);
|
|
217
|
+
return require(entry)(updater);
|
|
218
|
+
}
|
|
219
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
220
|
+
0 && (module.exports = {
|
|
221
|
+
createUpdater,
|
|
222
|
+
getAppAsarPath,
|
|
223
|
+
getAppVersion,
|
|
224
|
+
getElectronVersion,
|
|
225
|
+
getReleaseDnsPrefix,
|
|
226
|
+
initApp,
|
|
227
|
+
requireNative
|
|
228
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
type CheckResultType = 'success' | 'fail' | 'unavailable';
|
|
2
|
+
type UpdateEvents = {
|
|
3
|
+
check: null;
|
|
4
|
+
checkResult: [data: CheckResultType, err?: unknown];
|
|
5
|
+
downloadStart: [size: number];
|
|
6
|
+
downloading: [current: number];
|
|
7
|
+
downloadEnd: [success: boolean];
|
|
8
|
+
donwnloadError: [error: unknown];
|
|
9
|
+
};
|
|
10
|
+
type MaybeArray<T> = T extends undefined | null | never ? [] : T extends any[] ? T['length'] extends 1 ? [data: T[0]] : T : [data: T];
|
|
11
|
+
interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event extends Exclude<keyof T, number> = Exclude<keyof T, number>> {
|
|
12
|
+
removeAllListeners<E extends Event>(event?: E): this;
|
|
13
|
+
listeners<E extends Event>(eventName: E): Function[];
|
|
14
|
+
eventNames(): (Event)[];
|
|
15
|
+
on<E extends Event>(eventName: E, listener: (...data: MaybeArray<T[E]>) => void): this;
|
|
16
|
+
once<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
17
|
+
emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
|
|
18
|
+
off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
19
|
+
checkUpdate(releaseCdnPrefix?: string): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
type Updater = TypedUpdater<UpdateEvents>;
|
|
22
|
+
interface Options {
|
|
23
|
+
SIGNATURE_PUB: string;
|
|
24
|
+
productName: string;
|
|
25
|
+
githubRepository: string;
|
|
26
|
+
releaseCdnPrefix?: string;
|
|
27
|
+
}
|
|
28
|
+
declare function createUpdater({ SIGNATURE_PUB, githubRepository: repository, productName, releaseCdnPrefix, }: Options): Updater;
|
|
29
|
+
|
|
30
|
+
declare function getAppAsarPath(name: string): string;
|
|
31
|
+
declare function getElectronVersion(): string;
|
|
32
|
+
declare function getAppVersion(name: string): string;
|
|
33
|
+
declare function requireNative<T = any>(packageName: string): T;
|
|
34
|
+
declare function getReleaseDnsPrefix(): {
|
|
35
|
+
urlPrefix: string;
|
|
36
|
+
maintainer: string;
|
|
37
|
+
}[];
|
|
38
|
+
|
|
39
|
+
interface PathConfig {
|
|
40
|
+
/**
|
|
41
|
+
* path of electron output dist
|
|
42
|
+
* @default 'dist-electron'
|
|
43
|
+
*/
|
|
44
|
+
electronDistPath?: string;
|
|
45
|
+
/**
|
|
46
|
+
* relative path of main entry in electron dist
|
|
47
|
+
* @default 'main/index.js'
|
|
48
|
+
*/
|
|
49
|
+
mainPath?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Initialize application
|
|
53
|
+
* @param productName name of your application
|
|
54
|
+
* @param updater updater
|
|
55
|
+
* @param option options for entry, will be used to generate electron main path, default: `dist-electron/main/index.js`
|
|
56
|
+
* @returns a function to init your application with a updater
|
|
57
|
+
*/
|
|
58
|
+
declare function initApp(productName: string, updater: Updater, option?: PathConfig): any;
|
|
59
|
+
|
|
60
|
+
export { Options, Updater, createUpdater, getAppAsarPath, getAppVersion, getElectronVersion, getReleaseDnsPrefix, initApp, requireNative };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-AKU6F3WT.mjs";
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import { app as app3 } from "electron";
|
|
8
|
+
|
|
9
|
+
// src/utils.ts
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { app } from "electron";
|
|
13
|
+
function getAppAsarPath(name) {
|
|
14
|
+
return app.isPackaged ? join(dirname(app.getAppPath()), `${name}.asar`) : "dev";
|
|
15
|
+
}
|
|
16
|
+
function getElectronVersion() {
|
|
17
|
+
return app.getVersion();
|
|
18
|
+
}
|
|
19
|
+
function getAppVersion(name) {
|
|
20
|
+
return app.isPackaged ? readFileSync(join(getAppAsarPath(name), "version"), "utf-8").trim() : getElectronVersion();
|
|
21
|
+
}
|
|
22
|
+
function requireNative(packageName) {
|
|
23
|
+
const path = app.isPackaged ? join(app.getAppPath(), "node_modules", packageName) : packageName;
|
|
24
|
+
return __require(path);
|
|
25
|
+
}
|
|
26
|
+
function getReleaseDnsPrefix() {
|
|
27
|
+
const hub = "https://github.com";
|
|
28
|
+
return [
|
|
29
|
+
{ urlPrefix: `https://gh.gh2233.ml/${hub}`, maintainer: "@X.I.U/XIU2" },
|
|
30
|
+
{ urlPrefix: `https://ghproxy.com/${hub}`, maintainer: "gh-proxy" },
|
|
31
|
+
{ urlPrefix: `https://gh.ddlc.top/${hub}`, maintainer: "@mtr-static-official" },
|
|
32
|
+
{ urlPrefix: `https://ghdl.feizhuqwq.cf/${hub}`, maintainer: "feizhuqwq.com" },
|
|
33
|
+
{ urlPrefix: `https://slink.ltd/${hub}`, maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
34
|
+
{ urlPrefix: `https://git.xfj0.cn/${hub}`, maintainer: "anonymous1" },
|
|
35
|
+
{ urlPrefix: `https://gh.con.sh/${hub}`, maintainer: "anonymous2" },
|
|
36
|
+
{ urlPrefix: `https://ghps.cc/${hub}`, maintainer: "anonymous3" },
|
|
37
|
+
{ urlPrefix: "https://cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
38
|
+
{ urlPrefix: `https://hub.gitmirror.com/${hub}`, maintainer: "GitMirror" },
|
|
39
|
+
{ urlPrefix: `https://js.xxooo.ml/${hub}`, maintainer: "\u996D\u592A\u786C" },
|
|
40
|
+
{ urlPrefix: `https://proxy.freecdn.ml/?url=${hub}`, maintainer: "anonymous4" },
|
|
41
|
+
{ urlPrefix: "https://download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
42
|
+
{ urlPrefix: "https://download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
43
|
+
{ urlPrefix: "https://download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/updater.ts
|
|
48
|
+
import { EventEmitter } from "node:events";
|
|
49
|
+
import { Buffer } from "node:buffer";
|
|
50
|
+
import { createVerify } from "node:crypto";
|
|
51
|
+
import { createGunzip } from "node:zlib";
|
|
52
|
+
import { createReadStream, createWriteStream, existsSync } from "node:fs";
|
|
53
|
+
import { rm, writeFile } from "node:fs/promises";
|
|
54
|
+
import https from "node:https";
|
|
55
|
+
import { app as app2 } from "electron";
|
|
56
|
+
function createUpdater({
|
|
57
|
+
SIGNATURE_PUB,
|
|
58
|
+
githubRepository: repository,
|
|
59
|
+
productName,
|
|
60
|
+
releaseCdnPrefix
|
|
61
|
+
}) {
|
|
62
|
+
const updater = new EventEmitter();
|
|
63
|
+
async function download(url, format) {
|
|
64
|
+
const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
65
|
+
return await new Promise((resolve2, reject) => {
|
|
66
|
+
https.get(url, (res) => {
|
|
67
|
+
if (format === "json") {
|
|
68
|
+
let data = "";
|
|
69
|
+
res.setEncoding("utf8");
|
|
70
|
+
res.headers = {
|
|
71
|
+
Accept: "application/json",
|
|
72
|
+
UserAgent: ua
|
|
73
|
+
};
|
|
74
|
+
res.on("data", (chunk) => data += chunk);
|
|
75
|
+
res.on("end", () => {
|
|
76
|
+
resolve2(JSON.parse(data));
|
|
77
|
+
});
|
|
78
|
+
} else if (format === "buffer") {
|
|
79
|
+
let data = [];
|
|
80
|
+
res.headers = {
|
|
81
|
+
Accept: "application/octet-stream",
|
|
82
|
+
UserAgent: ua
|
|
83
|
+
};
|
|
84
|
+
res.on("data", (chunk) => {
|
|
85
|
+
updater.emit("downloading", chunk.length);
|
|
86
|
+
data.push(chunk);
|
|
87
|
+
});
|
|
88
|
+
res.on("end", () => {
|
|
89
|
+
updater.emit("downloadEnd", true);
|
|
90
|
+
resolve2(Buffer.concat(data));
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}).on("error", (e) => {
|
|
94
|
+
e && updater.emit("donwnloadError", e);
|
|
95
|
+
reject(e);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async function extractFile(gzipFilePath) {
|
|
100
|
+
if (!gzipFilePath.endsWith(".asar.gz") || !existsSync(gzipFilePath)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
gzipFilePath = gzipFilePath.replace(".asar.gz", ".tmp.gz");
|
|
104
|
+
return new Promise((resolve2, reject) => {
|
|
105
|
+
const gunzip = createGunzip();
|
|
106
|
+
const input = createReadStream(gzipFilePath);
|
|
107
|
+
const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
|
|
108
|
+
const output = createWriteStream(outputFilePath);
|
|
109
|
+
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
110
|
+
await rm(gzipFilePath);
|
|
111
|
+
resolve2(outputFilePath);
|
|
112
|
+
}).on("error", async (err) => {
|
|
113
|
+
await rm(gzipFilePath);
|
|
114
|
+
output.destroy(err);
|
|
115
|
+
reject(err);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function verify(buffer, signature) {
|
|
120
|
+
return createVerify("RSA-SHA256").update(buffer).verify(SIGNATURE_PUB, signature, "base64");
|
|
121
|
+
}
|
|
122
|
+
function needUpdate(version) {
|
|
123
|
+
const parseVersion = (version2) => {
|
|
124
|
+
const [major, minor, patch] = version2.split(".");
|
|
125
|
+
return ~~major * 100 + ~~minor * 10 + ~~patch;
|
|
126
|
+
};
|
|
127
|
+
return app2.isPackaged && parseVersion(app2.getVersion()) < parseVersion(version);
|
|
128
|
+
}
|
|
129
|
+
async function checkUpdate(releaseCdnPrefix2) {
|
|
130
|
+
const gzipPath = `../${productName}.asar.gz`;
|
|
131
|
+
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
132
|
+
const base = repository.replace("https://github.com", "");
|
|
133
|
+
const updateJSONUrl = `https://cdn.jsdelivr.net/gh/${base}/version.json`;
|
|
134
|
+
const downloadUrl = `${releaseCdnPrefix2 ? `${releaseCdnPrefix2}/${base}` : repository}/releases/download/latest/${productName}.asar.gz`;
|
|
135
|
+
if (existsSync(tmpFile)) {
|
|
136
|
+
await rm(tmpFile);
|
|
137
|
+
}
|
|
138
|
+
const json = await download(updateJSONUrl, "json");
|
|
139
|
+
if (!json) {
|
|
140
|
+
throw new Error("fetch update json failed");
|
|
141
|
+
}
|
|
142
|
+
const {
|
|
143
|
+
signature,
|
|
144
|
+
version,
|
|
145
|
+
size
|
|
146
|
+
} = json;
|
|
147
|
+
console.log(version, size, signature);
|
|
148
|
+
if (!needUpdate(version)) {
|
|
149
|
+
return "unavailable";
|
|
150
|
+
}
|
|
151
|
+
updater.emit("downloadStart", size);
|
|
152
|
+
const buffer = await download(downloadUrl, "buffer");
|
|
153
|
+
if (!verify(buffer, signature)) {
|
|
154
|
+
throw new Error("file broken, invalid signature!");
|
|
155
|
+
}
|
|
156
|
+
await writeFile(gzipPath, buffer);
|
|
157
|
+
await extractFile(gzipPath);
|
|
158
|
+
return "success";
|
|
159
|
+
}
|
|
160
|
+
const onCheck = async () => {
|
|
161
|
+
try {
|
|
162
|
+
const result = await checkUpdate(releaseCdnPrefix);
|
|
163
|
+
updater.emit("checkResult", result);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
updater.emit("checkResult", "fail", error);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
updater.on("check", onCheck);
|
|
169
|
+
updater.checkUpdate = onCheck;
|
|
170
|
+
return updater;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/index.ts
|
|
174
|
+
function initApp(productName, updater, option) {
|
|
175
|
+
const {
|
|
176
|
+
electronDistPath = "dist-electron",
|
|
177
|
+
mainPath = "main/index.js"
|
|
178
|
+
} = option ?? {};
|
|
179
|
+
const mainDir = app3.isPackaged ? `../${productName}.asar` : electronDistPath;
|
|
180
|
+
const entry = resolve(__dirname, mainDir, mainPath);
|
|
181
|
+
return __require(entry)(updater);
|
|
182
|
+
}
|
|
183
|
+
export {
|
|
184
|
+
createUpdater,
|
|
185
|
+
getAppAsarPath,
|
|
186
|
+
getAppVersion,
|
|
187
|
+
getElectronVersion,
|
|
188
|
+
getReleaseDnsPrefix,
|
|
189
|
+
initApp,
|
|
190
|
+
requireNative
|
|
191
|
+
};
|
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
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 key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || 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
|
+
// src/vite.ts
|
|
31
|
+
var vite_exports = {};
|
|
32
|
+
__export(vite_exports, {
|
|
33
|
+
default: () => vite_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(vite_exports);
|
|
36
|
+
var import_vite = require("vite");
|
|
37
|
+
|
|
38
|
+
// src/build-entry.ts
|
|
39
|
+
var import_node_fs = require("fs");
|
|
40
|
+
var import_promises = require("fs/promises");
|
|
41
|
+
var import_node_crypto = require("crypto");
|
|
42
|
+
var import_node_os = require("os");
|
|
43
|
+
var import_ci_info = require("ci-info");
|
|
44
|
+
var import_esbuild = require("esbuild");
|
|
45
|
+
async function generateKey(privateKeyPath, publicKeyPath, length) {
|
|
46
|
+
const pair = (0, import_node_crypto.generateKeyPairSync)("rsa", { modulusLength: length });
|
|
47
|
+
const privateKey = pair.privateKey.export({ type: "pkcs1", format: "pem" });
|
|
48
|
+
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
49
|
+
await (0, import_promises.writeFile)(privateKeyPath, privateKey);
|
|
50
|
+
await (0, import_promises.writeFile)(publicKeyPath, publicKey);
|
|
51
|
+
}
|
|
52
|
+
async function writePublicKeyToMain(updatePath, publicKeyPath) {
|
|
53
|
+
const file = await (0, import_promises.readFile)(updatePath, "utf-8");
|
|
54
|
+
const key = await (0, import_promises.readFile)(publicKeyPath, "utf-8");
|
|
55
|
+
const regex = /const SIGNATURE_PUB = ['`][\s\S]*?['`]/;
|
|
56
|
+
const replacement = `const SIGNATURE_PUB = \`${key}\``;
|
|
57
|
+
let replaced = file;
|
|
58
|
+
const signaturePubExists = regex.test(file);
|
|
59
|
+
if (signaturePubExists) {
|
|
60
|
+
replaced = file.replace(regex, replacement);
|
|
61
|
+
} else {
|
|
62
|
+
const lines = file.split(import_node_os.EOL);
|
|
63
|
+
const r = `${import_node_os.EOL}${replacement}${import_node_os.EOL}`;
|
|
64
|
+
let isMatched = false;
|
|
65
|
+
for (let i = 0; i < lines.length; i++) {
|
|
66
|
+
const line = lines[i];
|
|
67
|
+
if (!line.startsWith("import") && !line.startsWith("/")) {
|
|
68
|
+
lines.splice(i, 0, r);
|
|
69
|
+
isMatched = true;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
!isMatched && lines.push(r);
|
|
74
|
+
replaced = lines.join(import_node_os.EOL);
|
|
75
|
+
}
|
|
76
|
+
await (0, import_promises.writeFile)(updatePath, replaced);
|
|
77
|
+
}
|
|
78
|
+
async function buildEntry({
|
|
79
|
+
privateKeyPath,
|
|
80
|
+
publicKeyPath,
|
|
81
|
+
entryPath,
|
|
82
|
+
entryOutputPath: outfile,
|
|
83
|
+
minify,
|
|
84
|
+
keyLength
|
|
85
|
+
}) {
|
|
86
|
+
if (!import_ci_info.isCI) {
|
|
87
|
+
!(0, import_node_fs.existsSync)(privateKeyPath) && await generateKey(privateKeyPath, publicKeyPath, keyLength);
|
|
88
|
+
await writePublicKeyToMain(entryPath, publicKeyPath);
|
|
89
|
+
}
|
|
90
|
+
await (0, import_esbuild.build)({
|
|
91
|
+
entryPoints: [entryPath],
|
|
92
|
+
bundle: true,
|
|
93
|
+
platform: "node",
|
|
94
|
+
outfile,
|
|
95
|
+
minify,
|
|
96
|
+
external: ["electron"]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/build-asar.ts
|
|
101
|
+
var import_node_crypto2 = require("crypto");
|
|
102
|
+
var import_node_fs2 = require("fs");
|
|
103
|
+
var import_promises2 = require("fs/promises");
|
|
104
|
+
var import_node_zlib = __toESM(require("zlib"), 1);
|
|
105
|
+
var import_ci_info2 = require("ci-info");
|
|
106
|
+
function gzipFile(filePath) {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
const gzip = import_node_zlib.default.createGzip();
|
|
109
|
+
const input = (0, import_node_fs2.createReadStream)(filePath);
|
|
110
|
+
const output = (0, import_node_fs2.createWriteStream)(`${filePath}.gz`);
|
|
111
|
+
input.pipe(gzip).pipe(output).on("finish", () => resolve(null)).on("error", (err) => reject(err));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function generateSignature(buffer, privateKey) {
|
|
115
|
+
return (0, import_node_crypto2.createSign)("RSA-SHA256").update(buffer).sign({
|
|
116
|
+
key: privateKey,
|
|
117
|
+
padding: import_node_crypto2.constants.RSA_PKCS1_PADDING,
|
|
118
|
+
saltLength: import_node_crypto2.constants.RSA_PSS_SALTLEN_DIGEST
|
|
119
|
+
}, "base64");
|
|
120
|
+
}
|
|
121
|
+
async function pack(dir, target) {
|
|
122
|
+
let asar = null;
|
|
123
|
+
try {
|
|
124
|
+
asar = await import("asar");
|
|
125
|
+
} catch (ignore) {
|
|
126
|
+
}
|
|
127
|
+
if (!asar) {
|
|
128
|
+
try {
|
|
129
|
+
asar = await import("@electron/asar");
|
|
130
|
+
} catch (ignore) {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!asar) {
|
|
134
|
+
throw new Error("no asar, please install @electron/asar");
|
|
135
|
+
}
|
|
136
|
+
await asar.createPackage(dir, target);
|
|
137
|
+
}
|
|
138
|
+
async function buildAsar({
|
|
139
|
+
version,
|
|
140
|
+
asarOutputPath,
|
|
141
|
+
privateKeyPath,
|
|
142
|
+
electronDistPath,
|
|
143
|
+
rendererDistPath
|
|
144
|
+
}) {
|
|
145
|
+
await (0, import_promises2.rename)(rendererDistPath, `${electronDistPath}/renderer`);
|
|
146
|
+
await (0, import_promises2.writeFile)(`${electronDistPath}/version`, version);
|
|
147
|
+
await pack(electronDistPath, asarOutputPath);
|
|
148
|
+
if (import_ci_info2.isCI) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
await gzipFile(asarOutputPath);
|
|
152
|
+
const buffer = await (0, import_promises2.readFile)(`${asarOutputPath}.gz`);
|
|
153
|
+
const signature = generateSignature(buffer, await (0, import_promises2.readFile)(privateKeyPath, "utf-8"));
|
|
154
|
+
await (0, import_promises2.writeFile)("version.json", JSON.stringify({
|
|
155
|
+
signature,
|
|
156
|
+
version,
|
|
157
|
+
size: buffer.length
|
|
158
|
+
}, null, 2));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/option.ts
|
|
162
|
+
function parseOptions(options) {
|
|
163
|
+
const { isBuild, productName, version, minify = false, paths = {}, keys = {} } = options;
|
|
164
|
+
const {
|
|
165
|
+
entryPath = "electron/app.ts",
|
|
166
|
+
entryOutputPath = "app.js",
|
|
167
|
+
asarOutputPath = `release/${productName}.asar`,
|
|
168
|
+
electronDistPath = "dist-electron",
|
|
169
|
+
rendererDistPath = "dist"
|
|
170
|
+
} = paths;
|
|
171
|
+
const {
|
|
172
|
+
privateKeyPath = "public/private.pem",
|
|
173
|
+
publicKeyPath = "public/public.pem",
|
|
174
|
+
keyLength = 2048
|
|
175
|
+
} = keys;
|
|
176
|
+
const buildAsarOption = {
|
|
177
|
+
version,
|
|
178
|
+
productName,
|
|
179
|
+
asarOutputPath,
|
|
180
|
+
privateKeyPath,
|
|
181
|
+
electronDistPath,
|
|
182
|
+
rendererDistPath
|
|
183
|
+
};
|
|
184
|
+
const buildEntryOption = {
|
|
185
|
+
privateKeyPath,
|
|
186
|
+
publicKeyPath,
|
|
187
|
+
entryPath,
|
|
188
|
+
entryOutputPath,
|
|
189
|
+
minify,
|
|
190
|
+
keyLength
|
|
191
|
+
};
|
|
192
|
+
return { isBuild, buildAsarOption, buildEntryOption };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/vite.ts
|
|
196
|
+
function vite_default(options) {
|
|
197
|
+
const { isBuild, buildAsarOption, buildEntryOption } = parseOptions(options);
|
|
198
|
+
const { entryPath, entryOutputPath } = buildEntryOption;
|
|
199
|
+
const { asarOutputPath } = buildAsarOption;
|
|
200
|
+
const id = "electron-incremental-updater";
|
|
201
|
+
const log = (0, import_vite.createLogger)("info", { prefix: `[${id}]` });
|
|
202
|
+
return [
|
|
203
|
+
{
|
|
204
|
+
name: `vite-plugin-${id}-entry`,
|
|
205
|
+
async buildStart() {
|
|
206
|
+
log.info("build entry start");
|
|
207
|
+
await buildEntry(buildEntryOption);
|
|
208
|
+
log.info(`build entry end, ${entryPath} -> ${entryOutputPath}`);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: `vite-plugin-${id}-asar`,
|
|
213
|
+
async closeBundle() {
|
|
214
|
+
if (!isBuild) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
log.info("build asar start");
|
|
218
|
+
await buildAsar(buildAsarOption);
|
|
219
|
+
log.info(`build asar end, output to ${asarOutputPath}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
type Options = {
|
|
4
|
+
/**
|
|
5
|
+
* whether is in build mode
|
|
6
|
+
*/
|
|
7
|
+
isBuild: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* the name of you application
|
|
10
|
+
*
|
|
11
|
+
* you can set as 'name' in package.json
|
|
12
|
+
*/
|
|
13
|
+
productName: string;
|
|
14
|
+
/**
|
|
15
|
+
* the version of you application
|
|
16
|
+
*
|
|
17
|
+
* you can set as 'version' in package.json
|
|
18
|
+
*/
|
|
19
|
+
version: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to minify
|
|
22
|
+
*/
|
|
23
|
+
minify?: boolean;
|
|
24
|
+
paths?: {
|
|
25
|
+
/**
|
|
26
|
+
* Path to app entry file
|
|
27
|
+
* @default 'electron/app.ts'
|
|
28
|
+
*/
|
|
29
|
+
entryPath?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Path to app entry output file
|
|
32
|
+
* @default 'app.js'
|
|
33
|
+
*/
|
|
34
|
+
entryOutputPath?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Path to app entry file
|
|
37
|
+
* @default `release/${ProductName}.asar`
|
|
38
|
+
*/
|
|
39
|
+
asarOutputPath?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Path to electron build output
|
|
42
|
+
* @default `dist-electron`
|
|
43
|
+
*/
|
|
44
|
+
electronDistPath?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Path to renderer build output
|
|
47
|
+
* @default `dist`
|
|
48
|
+
*/
|
|
49
|
+
rendererDistPath?: string;
|
|
50
|
+
};
|
|
51
|
+
keys?: {
|
|
52
|
+
/**
|
|
53
|
+
* Path to the pem file that contains private key
|
|
54
|
+
* if not ended with .pem, it will be appended
|
|
55
|
+
* @default 'public/private.pem'
|
|
56
|
+
*/
|
|
57
|
+
privateKeyPath?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Path to the pem file that contains public key
|
|
60
|
+
* if not ended with .pem, it will be appended
|
|
61
|
+
* @default 'public/public.pem'
|
|
62
|
+
*/
|
|
63
|
+
publicKeyPath?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Length of the key
|
|
66
|
+
* @default 2048
|
|
67
|
+
*/
|
|
68
|
+
keyLength?: number;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
declare function export_default(options: Options): Plugin[];
|
|
73
|
+
|
|
74
|
+
export { export_default as default };
|
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import "./chunk-AKU6F3WT.mjs";
|
|
2
|
+
|
|
3
|
+
// src/vite.ts
|
|
4
|
+
import { createLogger } from "vite";
|
|
5
|
+
|
|
6
|
+
// src/build-entry.ts
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
9
|
+
import { generateKeyPairSync } from "node:crypto";
|
|
10
|
+
import { EOL } from "node:os";
|
|
11
|
+
import { isCI } from "ci-info";
|
|
12
|
+
import { build } from "esbuild";
|
|
13
|
+
async function generateKey(privateKeyPath, publicKeyPath, length) {
|
|
14
|
+
const pair = generateKeyPairSync("rsa", { modulusLength: length });
|
|
15
|
+
const privateKey = pair.privateKey.export({ type: "pkcs1", format: "pem" });
|
|
16
|
+
const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
|
|
17
|
+
await writeFile(privateKeyPath, privateKey);
|
|
18
|
+
await writeFile(publicKeyPath, publicKey);
|
|
19
|
+
}
|
|
20
|
+
async function writePublicKeyToMain(updatePath, publicKeyPath) {
|
|
21
|
+
const file = await readFile(updatePath, "utf-8");
|
|
22
|
+
const key = await readFile(publicKeyPath, "utf-8");
|
|
23
|
+
const regex = /const SIGNATURE_PUB = ['`][\s\S]*?['`]/;
|
|
24
|
+
const replacement = `const SIGNATURE_PUB = \`${key}\``;
|
|
25
|
+
let replaced = file;
|
|
26
|
+
const signaturePubExists = regex.test(file);
|
|
27
|
+
if (signaturePubExists) {
|
|
28
|
+
replaced = file.replace(regex, replacement);
|
|
29
|
+
} else {
|
|
30
|
+
const lines = file.split(EOL);
|
|
31
|
+
const r = `${EOL}${replacement}${EOL}`;
|
|
32
|
+
let isMatched = false;
|
|
33
|
+
for (let i = 0; i < lines.length; i++) {
|
|
34
|
+
const line = lines[i];
|
|
35
|
+
if (!line.startsWith("import") && !line.startsWith("/")) {
|
|
36
|
+
lines.splice(i, 0, r);
|
|
37
|
+
isMatched = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
!isMatched && lines.push(r);
|
|
42
|
+
replaced = lines.join(EOL);
|
|
43
|
+
}
|
|
44
|
+
await writeFile(updatePath, replaced);
|
|
45
|
+
}
|
|
46
|
+
async function buildEntry({
|
|
47
|
+
privateKeyPath,
|
|
48
|
+
publicKeyPath,
|
|
49
|
+
entryPath,
|
|
50
|
+
entryOutputPath: outfile,
|
|
51
|
+
minify,
|
|
52
|
+
keyLength
|
|
53
|
+
}) {
|
|
54
|
+
if (!isCI) {
|
|
55
|
+
!existsSync(privateKeyPath) && await generateKey(privateKeyPath, publicKeyPath, keyLength);
|
|
56
|
+
await writePublicKeyToMain(entryPath, publicKeyPath);
|
|
57
|
+
}
|
|
58
|
+
await build({
|
|
59
|
+
entryPoints: [entryPath],
|
|
60
|
+
bundle: true,
|
|
61
|
+
platform: "node",
|
|
62
|
+
outfile,
|
|
63
|
+
minify,
|
|
64
|
+
external: ["electron"]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/build-asar.ts
|
|
69
|
+
import { constants, createSign } from "node:crypto";
|
|
70
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
71
|
+
import { readFile as readFile2, rename, writeFile as writeFile2 } from "node:fs/promises";
|
|
72
|
+
import zlib from "node:zlib";
|
|
73
|
+
import { isCI as isCI2 } from "ci-info";
|
|
74
|
+
function gzipFile(filePath) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const gzip = zlib.createGzip();
|
|
77
|
+
const input = createReadStream(filePath);
|
|
78
|
+
const output = createWriteStream(`${filePath}.gz`);
|
|
79
|
+
input.pipe(gzip).pipe(output).on("finish", () => resolve(null)).on("error", (err) => reject(err));
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function generateSignature(buffer, privateKey) {
|
|
83
|
+
return createSign("RSA-SHA256").update(buffer).sign({
|
|
84
|
+
key: privateKey,
|
|
85
|
+
padding: constants.RSA_PKCS1_PADDING,
|
|
86
|
+
saltLength: constants.RSA_PSS_SALTLEN_DIGEST
|
|
87
|
+
}, "base64");
|
|
88
|
+
}
|
|
89
|
+
async function pack(dir, target) {
|
|
90
|
+
let asar = null;
|
|
91
|
+
try {
|
|
92
|
+
asar = await import("asar");
|
|
93
|
+
} catch (ignore) {
|
|
94
|
+
}
|
|
95
|
+
if (!asar) {
|
|
96
|
+
try {
|
|
97
|
+
asar = await import("@electron/asar");
|
|
98
|
+
} catch (ignore) {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!asar) {
|
|
102
|
+
throw new Error("no asar, please install @electron/asar");
|
|
103
|
+
}
|
|
104
|
+
await asar.createPackage(dir, target);
|
|
105
|
+
}
|
|
106
|
+
async function buildAsar({
|
|
107
|
+
version,
|
|
108
|
+
asarOutputPath,
|
|
109
|
+
privateKeyPath,
|
|
110
|
+
electronDistPath,
|
|
111
|
+
rendererDistPath
|
|
112
|
+
}) {
|
|
113
|
+
await rename(rendererDistPath, `${electronDistPath}/renderer`);
|
|
114
|
+
await writeFile2(`${electronDistPath}/version`, version);
|
|
115
|
+
await pack(electronDistPath, asarOutputPath);
|
|
116
|
+
if (isCI2) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
await gzipFile(asarOutputPath);
|
|
120
|
+
const buffer = await readFile2(`${asarOutputPath}.gz`);
|
|
121
|
+
const signature = generateSignature(buffer, await readFile2(privateKeyPath, "utf-8"));
|
|
122
|
+
await writeFile2("version.json", JSON.stringify({
|
|
123
|
+
signature,
|
|
124
|
+
version,
|
|
125
|
+
size: buffer.length
|
|
126
|
+
}, null, 2));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/option.ts
|
|
130
|
+
function parseOptions(options) {
|
|
131
|
+
const { isBuild, productName, version, minify = false, paths = {}, keys = {} } = options;
|
|
132
|
+
const {
|
|
133
|
+
entryPath = "electron/app.ts",
|
|
134
|
+
entryOutputPath = "app.js",
|
|
135
|
+
asarOutputPath = `release/${productName}.asar`,
|
|
136
|
+
electronDistPath = "dist-electron",
|
|
137
|
+
rendererDistPath = "dist"
|
|
138
|
+
} = paths;
|
|
139
|
+
const {
|
|
140
|
+
privateKeyPath = "public/private.pem",
|
|
141
|
+
publicKeyPath = "public/public.pem",
|
|
142
|
+
keyLength = 2048
|
|
143
|
+
} = keys;
|
|
144
|
+
const buildAsarOption = {
|
|
145
|
+
version,
|
|
146
|
+
productName,
|
|
147
|
+
asarOutputPath,
|
|
148
|
+
privateKeyPath,
|
|
149
|
+
electronDistPath,
|
|
150
|
+
rendererDistPath
|
|
151
|
+
};
|
|
152
|
+
const buildEntryOption = {
|
|
153
|
+
privateKeyPath,
|
|
154
|
+
publicKeyPath,
|
|
155
|
+
entryPath,
|
|
156
|
+
entryOutputPath,
|
|
157
|
+
minify,
|
|
158
|
+
keyLength
|
|
159
|
+
};
|
|
160
|
+
return { isBuild, buildAsarOption, buildEntryOption };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/vite.ts
|
|
164
|
+
function vite_default(options) {
|
|
165
|
+
const { isBuild, buildAsarOption, buildEntryOption } = parseOptions(options);
|
|
166
|
+
const { entryPath, entryOutputPath } = buildEntryOption;
|
|
167
|
+
const { asarOutputPath } = buildAsarOption;
|
|
168
|
+
const id = "electron-incremental-updater";
|
|
169
|
+
const log = createLogger("info", { prefix: `[${id}]` });
|
|
170
|
+
return [
|
|
171
|
+
{
|
|
172
|
+
name: `vite-plugin-${id}-entry`,
|
|
173
|
+
async buildStart() {
|
|
174
|
+
log.info("build entry start");
|
|
175
|
+
await buildEntry(buildEntryOption);
|
|
176
|
+
log.info(`build entry end, ${entryPath} -> ${entryOutputPath}`);
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: `vite-plugin-${id}-asar`,
|
|
181
|
+
async closeBundle() {
|
|
182
|
+
if (!isBuild) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
log.info("build asar start");
|
|
186
|
+
await buildAsar(buildAsarOption);
|
|
187
|
+
log.info(`build asar end, output to ${asarOutputPath}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
export {
|
|
193
|
+
vite_default as default
|
|
194
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "electron-incremental-update",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "electron incremental update tools, powered by vite",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsup",
|
|
7
|
+
"release": "bumpp"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"main": "dist/index.cjs",
|
|
15
|
+
"module": "dist/index.mjs",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"require": "./dist/index.cjs",
|
|
20
|
+
"import": "./dist/index.mjs"
|
|
21
|
+
},
|
|
22
|
+
"./vite": {
|
|
23
|
+
"require": "./dist/vite.cjs",
|
|
24
|
+
"import": "./dist/vite.mjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"typesVersions": {
|
|
28
|
+
"*": {
|
|
29
|
+
".": [
|
|
30
|
+
"dist/updater.d.ts"
|
|
31
|
+
],
|
|
32
|
+
"vite": [
|
|
33
|
+
"dist/vite.d.ts"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"electron",
|
|
39
|
+
"incremental update",
|
|
40
|
+
"updater"
|
|
41
|
+
],
|
|
42
|
+
"author": "",
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@electron/asar": "^3.2.4",
|
|
45
|
+
"@subframe7536/eslint-config": "^0.1.9",
|
|
46
|
+
"@types/node": "^20.2.5",
|
|
47
|
+
"asar": "^3.2.0",
|
|
48
|
+
"bumpp": "^9.1.1",
|
|
49
|
+
"electron": "^25.0.1",
|
|
50
|
+
"eslint": "^8.42.0",
|
|
51
|
+
"fs-jetpack": "^5.1.0",
|
|
52
|
+
"tsup": "^6.7.0",
|
|
53
|
+
"typescript": "^5.1.3",
|
|
54
|
+
"vite": "^4.3.9"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"ci-info": "^3.8.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@electron/asar": "*",
|
|
61
|
+
"asar": "*"
|
|
62
|
+
}
|
|
63
|
+
}
|