@kirill.konshin/electron 0.0.2 → 0.0.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"createWindow.d.ts","sourceRoot":"","sources":["../src/createWindow.ts"],"names":[],"mappings":"AAMA,OAAO,EAAa,aAAa,EAA8B,MAAM,UAAU,CAAC;AAKhF,eAAO,MAAM,KAAK,EAAE,OAAmD,CAAC;AACxE,eAAO,MAAM,OAAO,EAAE,MAAyB,CAAC;AAiBhD,wBAAgB,YAAY,CAAC,EACzB,KAAY,EACZ,MAAa,EACb,eAAsB,EACtB,uBAA8B,EAC9B,WAAkB,EAClB,MAAM,EACN,OAAO,EACP,YAAsC,EACtC,aAAkB,EAAE,yDAAyD;AAC7E,OAAsC,EAAE,+DAA+D;AACvG,cAAsB,EACtB,OAAe,EACf,cAAqB,GACxB,GAAE;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CACvB;yBA4KoB,aAAa,GAAG,IAAI;EAI7C"}
1
+ {"version":3,"file":"createWindow.d.ts","sourceRoot":"","sources":["../src/createWindow.ts"],"names":[],"mappings":"AAMA,OAAO,EAAa,aAAa,EAAmC,MAAM,UAAU,CAAC;AAKrF,eAAO,MAAM,KAAK,EAAE,OAAmD,CAAC;AACxE,eAAO,MAAM,OAAO,EAAE,MAAyB,CAAC;AAiBhD,wBAAgB,YAAY,CAAC,EACzB,KAAY,EACZ,MAAa,EACb,eAAsB,EACtB,uBAA8B,EAC9B,WAAkB,EAClB,MAAM,EACN,OAAO,EACP,YAAsC,EACtC,aAAkB,EAAE,yDAAyD;AAC7E,OAAsC,EAAE,+DAA+D;AACvG,cAAsB,EACtB,OAAe,EACf,cAAqB,GACxB,GAAE;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;CACvB;yBA4KoB,aAAa,GAAG,IAAI;EAI7C"}
@@ -1,160 +1,119 @@
1
+ import { checkForUpdates } from "./updater.js";
1
2
  import path from "node:path";
2
3
  import https from "node:https";
3
4
  import http from "node:http";
4
5
  import fs from "node:fs";
5
- import "node:fs/promises";
6
6
  import url from "node:url";
7
- import { app, BrowserWindow, protocol, shell, Menu } from "electron";
7
+ import { BrowserWindow, Menu, app, protocol, shell } from "electron";
8
8
  import defaultMenu from "electron-default-menu";
9
9
  import Store from "electron-store";
10
- import { checkForUpdates } from "./updater.js";
11
- const isDev = process.env["NODE_ENV"] === "development";
12
- const appPath = app.getAppPath();
13
- const FILE_NOT_FOUND = -6;
14
- function createWindow({
15
- width = 1e3,
16
- height = 1e3,
17
- disableSecurity = true,
18
- disableSecurityWarnings = true,
19
- quitOnClose = true,
20
- onOpen,
21
- onClose,
22
- localhostUrl = "http://localhost:3000",
23
- productionUrl = "",
24
- // in this mode Electron acts as a browser for remote app
25
- webPath = path.resolve(appPath, "web"),
26
- // must conform to what is in electron-builder.js files section
27
- useStaticInDev = false,
28
- updater = false,
29
- rememberBounds = true
30
- } = {}) {
31
- let mainWindow = null;
32
- console.log("[APP] Starting Electron", {
33
- isDev,
34
- appPath,
35
- useStaticInDev,
36
- localhostUrl,
37
- productionUrl,
38
- webPath,
39
- updater,
40
- rememberBounds,
41
- quitOnClose,
42
- disableSecurity,
43
- disableSecurityWarnings
44
- });
45
- if (!productionUrl && !webPath) {
46
- throw new Error("productionUrl or webPath must be defined");
47
- }
48
- if (productionUrl && webPath) {
49
- throw new Error("productionUrl and webPath cannot be used together");
50
- }
51
- if (!localhostUrl) {
52
- throw new Error("localhostUrl must be defined");
53
- }
54
- const store = new Store({
55
- schema: {
56
- bounds: {
57
- type: "object",
58
- properties: {
59
- // Docs: https://electronjs.org/docs/api/structures/rectangle
60
- height: { type: "number" },
61
- width: { type: "number" },
62
- x: { type: "number" },
63
- y: { type: "number" }
64
- }
65
- }
66
- }
67
- });
68
- if (disableSecurityWarnings) process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
69
- process.env["ELECTRON_ENABLE_LOGGING"] = "true";
70
- process.on("SIGTERM", () => process.exit(0));
71
- process.on("SIGINT", () => process.exit(0));
72
- const openDevTools = () => {
73
- if (!mainWindow) return;
74
- mainWindow.setSize(width + 800, height);
75
- mainWindow.center();
76
- mainWindow.webContents.openDevTools();
77
- };
78
- const createWindow2 = async () => {
79
- mainWindow = new BrowserWindow({
80
- width,
81
- height,
82
- icon: path.resolve(appPath, "assets/icon.png"),
83
- webPreferences: {
84
- nodeIntegration: false,
85
- // is default value after Electron v5
86
- contextIsolation: true,
87
- // protect against prototype pollution
88
- webSecurity: !disableSecurity,
89
- devTools: true
90
- },
91
- ...rememberBounds ? store.get("bounds") : {}
92
- });
93
- mainWindow.on("move", () => rememberBounds && mainWindow && store.set("bounds", mainWindow.getBounds()));
94
- mainWindow.once("ready-to-show", () => isDev && openDevTools());
95
- let interceptor = null;
96
- if (webPath && (!isDev || useStaticInDev)) {
97
- console.log(`[APP] Static Server Enabled, ${localhostUrl} will be intercepted to ${webPath}`);
98
- protocol.interceptStreamProtocol("http", (request, callback) => {
99
- if (request.url.startsWith(localhostUrl)) {
100
- let fileUrl = url.parse(request.url, false).pathname;
101
- if (!fileUrl) return callback({ error: FILE_NOT_FOUND });
102
- if (fileUrl === "/") fileUrl = "index.html";
103
- const filePath = path.join(webPath, fileUrl);
104
- const relativePath = path.relative(webPath, fileUrl);
105
- const isSafe = !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
106
- if (!isSafe && !isDev) return callback({ error: FILE_NOT_FOUND });
107
- console.log("[APP] Static Server", fileUrl, "->", filePath);
108
- callback(fs.createReadStream(filePath));
109
- return true;
110
- }
111
- (request.url.startsWith("https") ? https : http).get(request.url, callback);
112
- return true;
113
- });
114
- interceptor = () => protocol.uninterceptProtocol("http");
115
- }
116
- mainWindow.on("closed", () => {
117
- interceptor?.();
118
- onClose?.(mainWindow);
119
- mainWindow = null;
120
- interceptor = null;
121
- });
122
- mainWindow.webContents.setWindowOpenHandler(({ url: url2 }) => {
123
- shell.openExternal(url2).catch((e) => console.error(e));
124
- return { action: "deny" };
125
- });
126
- const menu = defaultMenu(app, shell);
127
- if (updater) {
128
- menu.at(-1).submenu.push(
129
- { type: "separator" },
130
- {
131
- label: "Check For Updates",
132
- click: checkForUpdates
133
- }
134
- );
135
- }
136
- Menu.setApplicationMenu(Menu.buildFromTemplate(menu));
137
- await app.whenReady();
138
- onOpen?.(mainWindow);
139
- if (!onOpen && localhostUrl) {
140
- await mainWindow.loadURL(productionUrl && !isDev ? productionUrl : `${localhostUrl}/`);
141
- }
142
- console.log("[APP] Main Window Open");
143
- };
144
- app.on("ready", createWindow2);
145
- app.on("window-all-closed", () => {
146
- if (process.platform !== "darwin" || quitOnClose) app.quit();
147
- });
148
- app.on("activate", () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow2());
149
- return {
150
- get mainWindow() {
151
- return mainWindow;
152
- }
153
- };
10
+ //#region src/createWindow.ts
11
+ var isDev = process.env.NODE_ENV === "development";
12
+ var appPath = app.getAppPath();
13
+ var FILE_NOT_FOUND = -6;
14
+ function createWindow({ width = 1e3, height = 1e3, disableSecurity = true, disableSecurityWarnings = true, quitOnClose = true, onOpen, onClose, localhostUrl = "http://localhost:3000", productionUrl = "", webPath = path.resolve(appPath, "web"), useStaticInDev = false, updater = false, rememberBounds = true } = {}) {
15
+ let mainWindow = null;
16
+ console.log("[APP] Starting Electron", {
17
+ isDev,
18
+ appPath,
19
+ useStaticInDev,
20
+ localhostUrl,
21
+ productionUrl,
22
+ webPath,
23
+ updater,
24
+ rememberBounds,
25
+ quitOnClose,
26
+ disableSecurity,
27
+ disableSecurityWarnings
28
+ });
29
+ if (!productionUrl && !webPath) throw new Error("productionUrl or webPath must be defined");
30
+ if (productionUrl && webPath) throw new Error("productionUrl and webPath cannot be used together");
31
+ if (!localhostUrl) throw new Error("localhostUrl must be defined");
32
+ const store = new Store({ schema: { bounds: {
33
+ type: "object",
34
+ properties: {
35
+ height: { type: "number" },
36
+ width: { type: "number" },
37
+ x: { type: "number" },
38
+ y: { type: "number" }
39
+ }
40
+ } } });
41
+ if (disableSecurityWarnings) process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
42
+ process.env["ELECTRON_ENABLE_LOGGING"] = "true";
43
+ process.on("SIGTERM", () => process.exit(0));
44
+ process.on("SIGINT", () => process.exit(0));
45
+ const openDevTools = () => {
46
+ if (!mainWindow) return;
47
+ mainWindow.setSize(width + 800, height);
48
+ mainWindow.center();
49
+ mainWindow.webContents.openDevTools();
50
+ };
51
+ const createWindow = async () => {
52
+ mainWindow = new BrowserWindow({
53
+ width,
54
+ height,
55
+ icon: path.resolve(appPath, "assets/icon.png"),
56
+ webPreferences: {
57
+ nodeIntegration: false,
58
+ contextIsolation: true,
59
+ webSecurity: !disableSecurity,
60
+ devTools: true
61
+ },
62
+ ...rememberBounds ? store.get("bounds") : {}
63
+ });
64
+ mainWindow.on("move", () => rememberBounds && mainWindow && store.set("bounds", mainWindow.getBounds()));
65
+ mainWindow.once("ready-to-show", () => isDev && openDevTools());
66
+ let interceptor = null;
67
+ if (webPath && (!isDev || useStaticInDev)) {
68
+ console.log(`[APP] Static Server Enabled, ${localhostUrl} will be intercepted to ${webPath}`);
69
+ protocol.interceptStreamProtocol("http", (request, callback) => {
70
+ if (request.url.startsWith(localhostUrl)) {
71
+ let fileUrl = url.parse(request.url, false).pathname;
72
+ if (!fileUrl) return callback({ error: FILE_NOT_FOUND });
73
+ if (fileUrl === "/") fileUrl = "index.html";
74
+ const filePath = path.join(webPath, fileUrl);
75
+ const relativePath = path.relative(webPath, fileUrl);
76
+ if (!(!relativePath.startsWith("..") && !path.isAbsolute(relativePath)) && !isDev) return callback({ error: FILE_NOT_FOUND });
77
+ console.log("[APP] Static Server", fileUrl, "->", filePath);
78
+ callback(fs.createReadStream(filePath));
79
+ return true;
80
+ }
81
+ (request.url.startsWith("https") ? https : http).get(request.url, callback);
82
+ return true;
83
+ });
84
+ interceptor = () => protocol.uninterceptProtocol("http");
85
+ }
86
+ mainWindow.on("closed", () => {
87
+ interceptor?.();
88
+ onClose?.(mainWindow);
89
+ mainWindow = null;
90
+ interceptor = null;
91
+ });
92
+ mainWindow.webContents.setWindowOpenHandler(({ url }) => {
93
+ shell.openExternal(url).catch((e) => console.error(e));
94
+ return { action: "deny" };
95
+ });
96
+ const menu = defaultMenu(app, shell);
97
+ if (updater) menu.at(-1).submenu.push({ type: "separator" }, {
98
+ label: "Check For Updates",
99
+ click: checkForUpdates
100
+ });
101
+ Menu.setApplicationMenu(Menu.buildFromTemplate(menu));
102
+ await app.whenReady();
103
+ onOpen?.(mainWindow);
104
+ if (!onOpen && localhostUrl) await mainWindow.loadURL(productionUrl && !isDev ? productionUrl : `${localhostUrl}/`);
105
+ console.log("[APP] Main Window Open");
106
+ };
107
+ app.on("ready", createWindow);
108
+ app.on("window-all-closed", () => {
109
+ if (process.platform !== "darwin" || quitOnClose) app.quit();
110
+ });
111
+ app.on("activate", () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow());
112
+ return { get mainWindow() {
113
+ return mainWindow;
114
+ } };
154
115
  }
155
- export {
156
- appPath,
157
- createWindow,
158
- isDev
159
- };
160
- //# sourceMappingURL=createWindow.js.map
116
+ //#endregion
117
+ export { appPath, createWindow, isDev };
118
+
119
+ //# sourceMappingURL=createWindow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createWindow.js","sources":["../src/createWindow.ts"],"sourcesContent":["import path from 'node:path';\nimport https from 'node:https';\nimport http from 'node:http';\nimport fs from 'node:fs';\nimport fsp from 'node:fs/promises';\nimport url from 'node:url';\nimport { Menu, app, BrowserWindow, shell, protocol, Rectangle } from 'electron';\nimport defaultMenu from 'electron-default-menu';\nimport Store from 'electron-store';\nimport { checkForUpdates } from './updater.js';\n\nexport const isDev: boolean = process.env['NODE_ENV'] === 'development';\nexport const appPath: string = app.getAppPath();\n\n// See https://cs.chromium.org/chromium/src/net/base/net_error_list.h\nconst FILE_NOT_FOUND = -6;\n\nconst getPath = async (path_, file = '') => {\n try {\n const result = await fsp.stat(path_);\n\n if (result.isFile()) return path_;\n\n if (result.isDirectory()) return getPath(path.join(path_, `${file}.html`));\n } catch {\n /* empty */\n }\n};\n\nexport function createWindow({\n width = 1000,\n height = 1000,\n disableSecurity = true,\n disableSecurityWarnings = true,\n quitOnClose = true,\n onOpen,\n onClose,\n localhostUrl = 'http://localhost:3000',\n productionUrl = '', // in this mode Electron acts as a browser for remote app\n webPath = path.resolve(appPath, 'web'), // must conform to what is in electron-builder.js files section\n useStaticInDev = false,\n updater = false,\n rememberBounds = true,\n}: {\n width?: number;\n height?: number;\n disableSecurity?: boolean;\n disableSecurityWarnings?: boolean;\n quitOnClose?: boolean;\n onOpen?: (win: BrowserWindow) => void;\n onClose?: (win: BrowserWindow) => void;\n localhostUrl?: string;\n productionUrl?: string;\n webPath?: string;\n useStaticInDev?: boolean;\n updater?: boolean;\n rememberBounds?: boolean;\n} = {}) {\n let mainWindow: BrowserWindow | null = null;\n\n console.log('[APP] Starting Electron', {\n isDev,\n appPath,\n useStaticInDev,\n localhostUrl,\n productionUrl,\n webPath,\n updater,\n rememberBounds,\n quitOnClose,\n disableSecurity,\n disableSecurityWarnings,\n });\n\n if (!productionUrl && !webPath) {\n throw new Error('productionUrl or webPath must be defined');\n }\n\n if (productionUrl && webPath) {\n throw new Error('productionUrl and webPath cannot be used together');\n }\n\n if (!localhostUrl) {\n throw new Error('localhostUrl must be defined');\n }\n\n const store = new Store<{ bounds: Rectangle }>({\n schema: {\n bounds: {\n type: 'object',\n properties: {\n // Docs: https://electronjs.org/docs/api/structures/rectangle\n height: { type: 'number' },\n width: { type: 'number' },\n x: { type: 'number' },\n y: { type: 'number' },\n },\n },\n },\n });\n\n if (disableSecurityWarnings) process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';\n process.env['ELECTRON_ENABLE_LOGGING'] = 'true';\n\n process.on('SIGTERM', () => process.exit(0));\n process.on('SIGINT', () => process.exit(0));\n\n const openDevTools = () => {\n if (!mainWindow) return;\n mainWindow.setSize(width + 800, height);\n mainWindow.center();\n mainWindow.webContents.openDevTools();\n };\n\n const createWindow = async () => {\n mainWindow = new BrowserWindow({\n width,\n height,\n icon: path.resolve(appPath, 'assets/icon.png'),\n webPreferences: {\n nodeIntegration: false, // is default value after Electron v5\n contextIsolation: true, // protect against prototype pollution\n webSecurity: !disableSecurity,\n devTools: true,\n },\n ...(rememberBounds ? store.get('bounds') : {}),\n });\n\n mainWindow.on('move', () => rememberBounds && mainWindow && store.set('bounds', mainWindow.getBounds()));\n\n mainWindow.once('ready-to-show', () => isDev && openDevTools());\n\n // Static interceptor\n\n let interceptor: (() => void) | null = null;\n\n if (webPath && (!isDev || useStaticInDev)) {\n console.log(`[APP] Static Server Enabled, ${localhostUrl} will be intercepted to ${webPath}`);\n\n //TODO https://localhost:3000\n // @see https://github.com/sindresorhus/electron-serve/blob/main/index.js\n protocol.interceptStreamProtocol('http', (request, callback) => {\n if (request.url.startsWith(localhostUrl)) {\n let fileUrl = url.parse(request.url, false).pathname;\n\n if (!fileUrl) return callback({ error: FILE_NOT_FOUND });\n\n if (fileUrl === '/') fileUrl = 'index.html';\n\n const filePath = path.join(webPath, fileUrl);\n\n const relativePath = path.relative(webPath, fileUrl);\n\n const isSafe = !relativePath.startsWith('..') && !path.isAbsolute(relativePath);\n\n if (!isSafe && !isDev) return callback({ error: FILE_NOT_FOUND });\n\n // const finalPath = await getPath(filePath, options.file);\n // const fileExtension = path.extname(filePath);\n\n console.log('[APP] Static Server', fileUrl, '->', filePath);\n\n // return {path: path.join(webPath, fileUrl)};\n callback(fs.createReadStream(filePath));\n\n return true;\n }\n\n // return {url: request.url};\n (request.url.startsWith('https') ? https : http).get(request.url, callback);\n\n return true;\n });\n\n interceptor = () => protocol.uninterceptProtocol('http');\n }\n\n mainWindow.on('closed', () => {\n interceptor?.();\n onClose?.(mainWindow as never);\n mainWindow = null;\n interceptor = null;\n });\n\n // External URLs\n\n mainWindow.webContents.setWindowOpenHandler(({ url }) => {\n shell.openExternal(url).catch((e) => console.error(e));\n return { action: 'deny' };\n });\n\n // Menu\n\n const menu = defaultMenu(app, shell);\n\n if (updater) {\n (menu.at(-1)!.submenu as any).push(\n { type: 'separator' },\n {\n label: 'Check For Updates',\n click: checkForUpdates,\n },\n );\n }\n\n Menu.setApplicationMenu(Menu.buildFromTemplate(menu)); //TODO onMenu\n\n // Should be last, after all listeners and menu\n\n await app.whenReady();\n\n onOpen?.(mainWindow);\n\n if (!onOpen && localhostUrl) {\n await mainWindow.loadURL(productionUrl && !isDev ? productionUrl : `${localhostUrl}/`);\n }\n\n console.log('[APP] Main Window Open');\n };\n\n app.on('ready', createWindow);\n\n app.on('window-all-closed', () => {\n if (process.platform !== 'darwin' || quitOnClose) app.quit();\n });\n\n app.on('activate', () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow());\n\n return {\n get mainWindow(): BrowserWindow | null {\n return mainWindow;\n },\n };\n}\n"],"names":["createWindow","url"],"mappings":"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"}
1
+ {"version":3,"file":"createWindow.js","names":[],"sources":["../src/createWindow.ts"],"sourcesContent":["import path from 'node:path';\nimport https from 'node:https';\nimport http from 'node:http';\nimport fs from 'node:fs';\nimport fsp from 'node:fs/promises';\nimport url from 'node:url';\nimport { Menu, app, BrowserWindow, shell, protocol, type Rectangle } from 'electron';\nimport defaultMenu from 'electron-default-menu';\nimport Store from 'electron-store';\nimport { checkForUpdates } from './updater.js';\n\nexport const isDev: boolean = process.env['NODE_ENV'] === 'development';\nexport const appPath: string = app.getAppPath();\n\n// See https://cs.chromium.org/chromium/src/net/base/net_error_list.h\nconst FILE_NOT_FOUND = -6;\n\nconst getPath = async (path_, file = '') => {\n try {\n const result = await fsp.stat(path_);\n\n if (result.isFile()) return path_;\n\n if (result.isDirectory()) return getPath(path.join(path_, `${file}.html`));\n } catch {\n /* empty */\n }\n};\n\nexport function createWindow({\n width = 1000,\n height = 1000,\n disableSecurity = true,\n disableSecurityWarnings = true,\n quitOnClose = true,\n onOpen,\n onClose,\n localhostUrl = 'http://localhost:3000',\n productionUrl = '', // in this mode Electron acts as a browser for remote app\n webPath = path.resolve(appPath, 'web'), // must conform to what is in electron-builder.js files section\n useStaticInDev = false,\n updater = false,\n rememberBounds = true,\n}: {\n width?: number;\n height?: number;\n disableSecurity?: boolean;\n disableSecurityWarnings?: boolean;\n quitOnClose?: boolean;\n onOpen?: (win: BrowserWindow) => void;\n onClose?: (win: BrowserWindow) => void;\n localhostUrl?: string;\n productionUrl?: string;\n webPath?: string;\n useStaticInDev?: boolean;\n updater?: boolean;\n rememberBounds?: boolean;\n} = {}) {\n let mainWindow: BrowserWindow | null = null;\n\n console.log('[APP] Starting Electron', {\n isDev,\n appPath,\n useStaticInDev,\n localhostUrl,\n productionUrl,\n webPath,\n updater,\n rememberBounds,\n quitOnClose,\n disableSecurity,\n disableSecurityWarnings,\n });\n\n if (!productionUrl && !webPath) {\n throw new Error('productionUrl or webPath must be defined');\n }\n\n if (productionUrl && webPath) {\n throw new Error('productionUrl and webPath cannot be used together');\n }\n\n if (!localhostUrl) {\n throw new Error('localhostUrl must be defined');\n }\n\n const store = new Store<{ bounds: Rectangle }>({\n schema: {\n bounds: {\n type: 'object',\n properties: {\n // Docs: https://electronjs.org/docs/api/structures/rectangle\n height: { type: 'number' },\n width: { type: 'number' },\n x: { type: 'number' },\n y: { type: 'number' },\n },\n },\n },\n });\n\n if (disableSecurityWarnings) process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';\n process.env['ELECTRON_ENABLE_LOGGING'] = 'true';\n\n process.on('SIGTERM', () => process.exit(0));\n process.on('SIGINT', () => process.exit(0));\n\n const openDevTools = () => {\n if (!mainWindow) return;\n mainWindow.setSize(width + 800, height);\n mainWindow.center();\n mainWindow.webContents.openDevTools();\n };\n\n const createWindow = async () => {\n mainWindow = new BrowserWindow({\n width,\n height,\n icon: path.resolve(appPath, 'assets/icon.png'),\n webPreferences: {\n nodeIntegration: false, // is default value after Electron v5\n contextIsolation: true, // protect against prototype pollution\n webSecurity: !disableSecurity,\n devTools: true,\n },\n ...(rememberBounds ? store.get('bounds') : {}),\n });\n\n mainWindow.on('move', () => rememberBounds && mainWindow && store.set('bounds', mainWindow.getBounds()));\n\n mainWindow.once('ready-to-show', () => isDev && openDevTools());\n\n // Static interceptor\n\n let interceptor: (() => void) | null = null;\n\n if (webPath && (!isDev || useStaticInDev)) {\n console.log(`[APP] Static Server Enabled, ${localhostUrl} will be intercepted to ${webPath}`);\n\n //TODO https://localhost:3000\n // @see https://github.com/sindresorhus/electron-serve/blob/main/index.js\n protocol.interceptStreamProtocol('http', (request, callback) => {\n if (request.url.startsWith(localhostUrl)) {\n let fileUrl = url.parse(request.url, false).pathname;\n\n if (!fileUrl) return callback({ error: FILE_NOT_FOUND });\n\n if (fileUrl === '/') fileUrl = 'index.html';\n\n const filePath = path.join(webPath, fileUrl);\n\n const relativePath = path.relative(webPath, fileUrl);\n\n const isSafe = !relativePath.startsWith('..') && !path.isAbsolute(relativePath);\n\n if (!isSafe && !isDev) return callback({ error: FILE_NOT_FOUND });\n\n // const finalPath = await getPath(filePath, options.file);\n // const fileExtension = path.extname(filePath);\n\n console.log('[APP] Static Server', fileUrl, '->', filePath);\n\n // return {path: path.join(webPath, fileUrl)};\n callback(fs.createReadStream(filePath));\n\n return true;\n }\n\n // return {url: request.url};\n (request.url.startsWith('https') ? https : http).get(request.url, callback);\n\n return true;\n });\n\n interceptor = () => protocol.uninterceptProtocol('http');\n }\n\n mainWindow.on('closed', () => {\n interceptor?.();\n onClose?.(mainWindow as never);\n mainWindow = null;\n interceptor = null;\n });\n\n // External URLs\n\n mainWindow.webContents.setWindowOpenHandler(({ url }) => {\n shell.openExternal(url).catch((e) => console.error(e));\n return { action: 'deny' };\n });\n\n // Menu\n\n const menu = defaultMenu(app, shell);\n\n if (updater) {\n (menu.at(-1)!.submenu as any).push(\n { type: 'separator' },\n {\n label: 'Check For Updates',\n click: checkForUpdates,\n },\n );\n }\n\n Menu.setApplicationMenu(Menu.buildFromTemplate(menu)); //TODO onMenu\n\n // Should be last, after all listeners and menu\n\n await app.whenReady();\n\n onOpen?.(mainWindow);\n\n if (!onOpen && localhostUrl) {\n await mainWindow.loadURL(productionUrl && !isDev ? productionUrl : `${localhostUrl}/`);\n }\n\n console.log('[APP] Main Window Open');\n };\n\n app.on('ready', createWindow);\n\n app.on('window-all-closed', () => {\n if (process.platform !== 'darwin' || quitOnClose) app.quit();\n });\n\n app.on('activate', () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow());\n\n return {\n get mainWindow(): BrowserWindow | null {\n return mainWindow;\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAa,QAAA,QAAA,IAAA,aAA6C;AAC1D,IAAa,UAAkB,IAAI,WAAW;AAG9C,IAAM,iBAAiB;AAcvB,SAAgB,aAAa,EACzB,QAAQ,KACR,SAAS,KACT,kBAAkB,MAClB,0BAA0B,MAC1B,cAAc,MACd,QACA,SACA,eAAe,yBACf,gBAAgB,IAChB,UAAU,KAAK,QAAQ,SAAS,KAAK,GACrC,iBAAiB,OACjB,UAAU,OACV,iBAAiB,SAejB,CAAC,GAAG;CACJ,IAAI,aAAmC;CAEvC,QAAQ,IAAI,2BAA2B;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACJ,CAAC;CAED,IAAI,CAAC,iBAAiB,CAAC,SACnB,MAAM,IAAI,MAAM,0CAA0C;CAG9D,IAAI,iBAAiB,SACjB,MAAM,IAAI,MAAM,mDAAmD;CAGvE,IAAI,CAAC,cACD,MAAM,IAAI,MAAM,8BAA8B;CAGlD,MAAM,QAAQ,IAAI,MAA6B,EAC3C,QAAQ,EACJ,QAAQ;EACJ,MAAM;EACN,YAAY;GAER,QAAQ,EAAE,MAAM,SAAS;GACzB,OAAO,EAAE,MAAM,SAAS;GACxB,GAAG,EAAE,MAAM,SAAS;GACpB,GAAG,EAAE,MAAM,SAAS;EACxB;CACJ,EACJ,EACJ,CAAC;CAED,IAAI,yBAAyB,QAAQ,IAAI,wCAAwC;CACjF,QAAQ,IAAI,6BAA6B;CAEzC,QAAQ,GAAG,iBAAiB,QAAQ,KAAK,CAAC,CAAC;CAC3C,QAAQ,GAAG,gBAAgB,QAAQ,KAAK,CAAC,CAAC;CAE1C,MAAM,qBAAqB;EACvB,IAAI,CAAC,YAAY;EACjB,WAAW,QAAQ,QAAQ,KAAK,MAAM;EACtC,WAAW,OAAO;EAClB,WAAW,YAAY,aAAa;CACxC;CAEA,MAAM,eAAe,YAAY;EAC7B,aAAa,IAAI,cAAc;GAC3B;GACA;GACA,MAAM,KAAK,QAAQ,SAAS,iBAAiB;GAC7C,gBAAgB;IACZ,iBAAiB;IACjB,kBAAkB;IAClB,aAAa,CAAC;IACd,UAAU;GACd;GACA,GAAI,iBAAiB,MAAM,IAAI,QAAQ,IAAI,CAAC;EAChD,CAAC;EAED,WAAW,GAAG,cAAc,kBAAkB,cAAc,MAAM,IAAI,UAAU,WAAW,UAAU,CAAC,CAAC;EAEvG,WAAW,KAAK,uBAAuB,SAAS,aAAa,CAAC;EAI9D,IAAI,cAAmC;EAEvC,IAAI,YAAY,CAAC,SAAS,iBAAiB;GACvC,QAAQ,IAAI,gCAAgC,aAAa,0BAA0B,SAAS;GAI5F,SAAS,wBAAwB,SAAS,SAAS,aAAa;IAC5D,IAAI,QAAQ,IAAI,WAAW,YAAY,GAAG;KACtC,IAAI,UAAU,IAAI,MAAM,QAAQ,KAAK,KAAK,CAAC,CAAC;KAE5C,IAAI,CAAC,SAAS,OAAO,SAAS,EAAE,OAAO,eAAe,CAAC;KAEvD,IAAI,YAAY,KAAK,UAAU;KAE/B,MAAM,WAAW,KAAK,KAAK,SAAS,OAAO;KAE3C,MAAM,eAAe,KAAK,SAAS,SAAS,OAAO;KAInD,IAAI,EAFW,CAAC,aAAa,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,YAAY,MAE/D,CAAC,OAAO,OAAO,SAAS,EAAE,OAAO,eAAe,CAAC;KAKhE,QAAQ,IAAI,uBAAuB,SAAS,MAAM,QAAQ;KAG1D,SAAS,GAAG,iBAAiB,QAAQ,CAAC;KAEtC,OAAO;IACX;IAGA,CAAC,QAAQ,IAAI,WAAW,OAAO,IAAI,QAAQ,KAAA,CAAM,IAAI,QAAQ,KAAK,QAAQ;IAE1E,OAAO;GACX,CAAC;GAED,oBAAoB,SAAS,oBAAoB,MAAM;EAC3D;EAEA,WAAW,GAAG,gBAAgB;GAC1B,cAAc;GACd,UAAU,UAAmB;GAC7B,aAAa;GACb,cAAc;EAClB,CAAC;EAID,WAAW,YAAY,sBAAsB,EAAE,UAAU;GACrD,MAAM,aAAa,GAAG,CAAC,CAAC,OAAO,MAAM,QAAQ,MAAM,CAAC,CAAC;GACrD,OAAO,EAAE,QAAQ,OAAO;EAC5B,CAAC;EAID,MAAM,OAAO,YAAY,KAAK,KAAK;EAEnC,IAAI,SACA,KAAM,GAAG,EAAE,CAAC,CAAE,QAAgB,KAC1B,EAAE,MAAM,YAAY,GACpB;GACI,OAAO;GACP,OAAO;EACX,CACJ;EAGJ,KAAK,mBAAmB,KAAK,kBAAkB,IAAI,CAAC;EAIpD,MAAM,IAAI,UAAU;EAEpB,SAAS,UAAU;EAEnB,IAAI,CAAC,UAAU,cACX,MAAM,WAAW,QAAQ,iBAAiB,CAAC,QAAQ,gBAAgB,GAAG,aAAa,EAAE;EAGzF,QAAQ,IAAI,wBAAwB;CACxC;CAEA,IAAI,GAAG,SAAS,YAAY;CAE5B,IAAI,GAAG,2BAA2B;EAC9B,IAAI,QAAQ,aAAa,YAAY,aAAa,IAAI,KAAK;CAC/D,CAAC;CAED,IAAI,GAAG,kBAAkB,cAAc,cAAc,CAAC,CAAC,WAAW,KAAK,CAAC,cAAc,aAAa,CAAC;CAEpG,OAAO,EACH,IAAI,aAAmC;EACnC,OAAO;CACX,EACJ;AACJ"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './createWindow';
2
- export * from './updater';
1
+ export * from './createWindow.js';
2
+ export * from './updater.js';
3
3
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,9 +1,3 @@
1
- import { appPath, createWindow, isDev } from "./createWindow.js";
2
1
  import { checkForUpdates } from "./updater.js";
3
- export {
4
- appPath,
5
- checkForUpdates,
6
- createWindow,
7
- isDev
8
- };
9
- //# sourceMappingURL=index.js.map
2
+ import { appPath, createWindow, isDev } from "./createWindow.js";
3
+ export { appPath, checkForUpdates, createWindow, isDev };
package/dist/updater.js CHANGED
@@ -1,46 +1,47 @@
1
1
  import { dialog } from "electron";
2
2
  import { autoUpdater } from "electron-updater";
3
- let updateButton;
3
+ //#region src/updater.ts
4
+ var updateButton;
4
5
  autoUpdater.autoDownload = false;
5
6
  autoUpdater.on("error", (error) => {
6
- dialog.showErrorBox("Error: ", !error ? "unknown" : (error.stack || error).toString());
7
+ dialog.showErrorBox("Error: ", !error ? "unknown" : (error.stack || error).toString());
7
8
  });
8
9
  autoUpdater.on("update-available", async () => {
9
- const { response } = await dialog.showMessageBox({
10
- type: "info",
11
- title: "Found Updates",
12
- message: "Found updates, do you want update now?",
13
- buttons: ["Yes", "No"]
14
- });
15
- updateButton.enabled = true;
16
- updateButton = null;
17
- if (response === 0) await autoUpdater.downloadUpdate();
10
+ const { response } = await dialog.showMessageBox({
11
+ type: "info",
12
+ title: "Found Updates",
13
+ message: "Found updates, do you want update now?",
14
+ buttons: ["Yes", "No"]
15
+ });
16
+ updateButton.enabled = true;
17
+ updateButton = null;
18
+ if (response === 0) await autoUpdater.downloadUpdate();
18
19
  });
19
20
  autoUpdater.on("update-not-available", async () => {
20
- try {
21
- await dialog.showMessageBox({
22
- title: "No Updates",
23
- message: "Current version is up-to-date."
24
- });
25
- } catch (e) {
26
- dialog.showErrorBox("Error: ", e.toString());
27
- }
28
- updateButton.enabled = true;
29
- updateButton = null;
21
+ try {
22
+ await dialog.showMessageBox({
23
+ title: "No Updates",
24
+ message: "Current version is up-to-date."
25
+ });
26
+ } catch (e) {
27
+ dialog.showErrorBox("Error: ", e.toString());
28
+ }
29
+ updateButton.enabled = true;
30
+ updateButton = null;
30
31
  });
31
32
  autoUpdater.on("update-downloaded", async () => {
32
- await dialog.showMessageBox({
33
- title: "Install Update",
34
- message: "Update downloaded, application will quit for update..."
35
- });
36
- autoUpdater.quitAndInstall();
33
+ await dialog.showMessageBox({
34
+ title: "Install Update",
35
+ message: "Update downloaded, application will quit for update..."
36
+ });
37
+ autoUpdater.quitAndInstall();
37
38
  });
38
39
  function checkForUpdates(menuItem) {
39
- updateButton = menuItem;
40
- updateButton.enabled = false;
41
- autoUpdater.checkForUpdates().catch((e) => console.error("Update error", e));
40
+ updateButton = menuItem;
41
+ updateButton.enabled = false;
42
+ autoUpdater.checkForUpdates().catch((e) => console.error("Update error", e));
42
43
  }
43
- export {
44
- checkForUpdates
45
- };
46
- //# sourceMappingURL=updater.js.map
44
+ //#endregion
45
+ export { checkForUpdates };
46
+
47
+ //# sourceMappingURL=updater.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"updater.js","sources":["../src/updater.ts"],"sourcesContent":["// https://github.com/electron-userland/electron-builder/blob/docs-deprecated/encapsulated%20manual%20update%20via%20menu.js\nimport { dialog } from 'electron';\nimport { autoUpdater } from 'electron-updater';\n\nlet updateButton;\n\nautoUpdater.autoDownload = false;\n\nautoUpdater.on('error', (error) => {\n dialog.showErrorBox('Error: ', !error ? 'unknown' : (error.stack || error).toString());\n});\n\nautoUpdater.on('update-available', async () => {\n const { response } = await dialog.showMessageBox({\n type: 'info',\n title: 'Found Updates',\n message: 'Found updates, do you want update now?',\n buttons: ['Yes', 'No'],\n });\n\n updateButton.enabled = true;\n updateButton = null;\n\n if (response === 0) await autoUpdater.downloadUpdate();\n});\n\nautoUpdater.on('update-not-available', async () => {\n try {\n await dialog.showMessageBox({\n title: 'No Updates',\n message: 'Current version is up-to-date.',\n });\n } catch (e) {\n dialog.showErrorBox('Error: ', e.toString());\n }\n updateButton.enabled = true;\n updateButton = null;\n});\n\nautoUpdater.on('update-downloaded', async () => {\n await dialog.showMessageBox({\n title: 'Install Update',\n message: 'Update downloaded, application will quit for update...',\n });\n\n autoUpdater.quitAndInstall();\n});\n\nexport function checkForUpdates(menuItem: any): void {\n updateButton = menuItem;\n updateButton.enabled = false;\n autoUpdater.checkForUpdates().catch((e) => console.error('Update error', e));\n}\n"],"names":[],"mappings":";;AAIA,IAAI;AAEJ,YAAY,eAAe;AAE3B,YAAY,GAAG,SAAS,CAAC,UAAU;AAC/B,SAAO,aAAa,WAAW,CAAC,QAAQ,aAAa,MAAM,SAAS,OAAO,UAAU;AACzF,CAAC;AAED,YAAY,GAAG,oBAAoB,YAAY;AAC3C,QAAM,EAAE,SAAA,IAAa,MAAM,OAAO,eAAe;AAAA,IAC7C,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS,CAAC,OAAO,IAAI;AAAA,EAAA,CACxB;AAED,eAAa,UAAU;AACvB,iBAAe;AAEf,MAAI,aAAa,EAAG,OAAM,YAAY,eAAA;AAC1C,CAAC;AAED,YAAY,GAAG,wBAAwB,YAAY;AAC/C,MAAI;AACA,UAAM,OAAO,eAAe;AAAA,MACxB,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACZ;AAAA,EACL,SAAS,GAAG;AACR,WAAO,aAAa,WAAW,EAAE,SAAA,CAAU;AAAA,EAC/C;AACA,eAAa,UAAU;AACvB,iBAAe;AACnB,CAAC;AAED,YAAY,GAAG,qBAAqB,YAAY;AAC5C,QAAM,OAAO,eAAe;AAAA,IACxB,OAAO;AAAA,IACP,SAAS;AAAA,EAAA,CACZ;AAED,cAAY,eAAA;AAChB,CAAC;AAEM,SAAS,gBAAgB,UAAqB;AACjD,iBAAe;AACf,eAAa,UAAU;AACvB,cAAY,kBAAkB,MAAM,CAAC,MAAM,QAAQ,MAAM,gBAAgB,CAAC,CAAC;AAC/E;"}
1
+ {"version":3,"file":"updater.js","names":[],"sources":["../src/updater.ts"],"sourcesContent":["// https://github.com/electron-userland/electron-builder/blob/docs-deprecated/encapsulated%20manual%20update%20via%20menu.js\nimport { dialog } from 'electron';\nimport { autoUpdater } from 'electron-updater';\n\nlet updateButton;\n\nautoUpdater.autoDownload = false;\n\nautoUpdater.on('error', (error) => {\n dialog.showErrorBox('Error: ', !error ? 'unknown' : (error.stack || error).toString());\n});\n\nautoUpdater.on('update-available', async () => {\n const { response } = await dialog.showMessageBox({\n type: 'info',\n title: 'Found Updates',\n message: 'Found updates, do you want update now?',\n buttons: ['Yes', 'No'],\n });\n\n updateButton.enabled = true;\n updateButton = null;\n\n if (response === 0) await autoUpdater.downloadUpdate();\n});\n\nautoUpdater.on('update-not-available', async () => {\n try {\n await dialog.showMessageBox({\n title: 'No Updates',\n message: 'Current version is up-to-date.',\n });\n } catch (e) {\n dialog.showErrorBox('Error: ', e.toString());\n }\n updateButton.enabled = true;\n updateButton = null;\n});\n\nautoUpdater.on('update-downloaded', async () => {\n await dialog.showMessageBox({\n title: 'Install Update',\n message: 'Update downloaded, application will quit for update...',\n });\n\n autoUpdater.quitAndInstall();\n});\n\nexport function checkForUpdates(menuItem: any): void {\n updateButton = menuItem;\n updateButton.enabled = false;\n autoUpdater.checkForUpdates().catch((e) => console.error('Update error', e));\n}\n"],"mappings":";;;AAIA,IAAI;AAEJ,YAAY,eAAe;AAE3B,YAAY,GAAG,UAAU,UAAU;CAC/B,OAAO,aAAa,WAAW,CAAC,QAAQ,aAAa,MAAM,SAAS,MAAA,CAAO,SAAS,CAAC;AACzF,CAAC;AAED,YAAY,GAAG,oBAAoB,YAAY;CAC3C,MAAM,EAAE,aAAa,MAAM,OAAO,eAAe;EAC7C,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS,CAAC,OAAO,IAAI;CACzB,CAAC;CAED,aAAa,UAAU;CACvB,eAAe;CAEf,IAAI,aAAa,GAAG,MAAM,YAAY,eAAe;AACzD,CAAC;AAED,YAAY,GAAG,wBAAwB,YAAY;CAC/C,IAAI;EACA,MAAM,OAAO,eAAe;GACxB,OAAO;GACP,SAAS;EACb,CAAC;CACL,SAAS,GAAG;EACR,OAAO,aAAa,WAAW,EAAE,SAAS,CAAC;CAC/C;CACA,aAAa,UAAU;CACvB,eAAe;AACnB,CAAC;AAED,YAAY,GAAG,qBAAqB,YAAY;CAC5C,MAAM,OAAO,eAAe;EACxB,OAAO;EACP,SAAS;CACb,CAAC;CAED,YAAY,eAAe;AAC/B,CAAC;AAED,SAAgB,gBAAgB,UAAqB;CACjD,eAAe;CACf,aAAa,UAAU;CACvB,YAAY,gBAAgB,CAAC,CAAC,OAAO,MAAM,QAAQ,MAAM,gBAAgB,CAAC,CAAC;AAC/E"}
package/package.json CHANGED
@@ -1,18 +1,16 @@
1
1
  {
2
2
  "name": "@kirill.konshin/electron",
3
3
  "description": "Utilities",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "----- BUILD -----": "",
8
8
  "clean": "rm -rf dist .tscache tsconfig.tsbuildinfo",
9
9
  "build": "vite build",
10
- "build:index": "ctix build",
11
- "build:check-types": "attw --pack .",
12
10
  "start": "yarn build --watch",
13
11
  "wait": "wait-on ./dist/index.js",
14
12
  "----- TEST -----": "",
15
- "test:disabled": "vitest run --coverage",
13
+ "test": "vitest run --coverage",
16
14
  "test:watch": "vitest watch --coverage",
17
15
  "----- STORYBOOK -----": "",
18
16
  "storybook:start": "storybook dev -p 6006",
@@ -50,5 +48,18 @@
50
48
  },
51
49
  "main": "./dist/index.js",
52
50
  "module": "./dist/index.js",
53
- "types": "./dist/index.d.ts"
51
+ "types": "./dist/index.d.ts",
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/kirill-konshin/utils.git",
55
+ "directory": "packages/electron"
56
+ },
57
+ "nx": {
58
+ "tags": [
59
+ "platform:electron"
60
+ ]
61
+ },
62
+ "files": [
63
+ "dist"
64
+ ]
54
65
  }
package/.ctirc DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "options": [
3
- {
4
- "mode": "create",
5
- "project": "tsconfig.json",
6
- "include": "src/**/*.{ts,tsx}",
7
- "exclude": [
8
- "**/*.stories.*",
9
- "**/*.test.*",
10
- "**/*.fixture.*"
11
- ],
12
- "startFrom": "src",
13
- "backup": false,
14
- "overwrite": true,
15
- "generationStyle": "default-alias-named-star",
16
- "output": "src",
17
- "verbose": true
18
- }
19
- ]
20
- }
@@ -1,21 +0,0 @@
1
- vite v7.0.6 building SSR bundle for production...
2
- - ctix 'create' mode start, ...
3
- ✔ /home/runner/work/utils/utils/packages/electron/tsconfig.json loading complete!
4
- ✔ analysis export statements completed!
5
- - build "index.ts" file start
6
- - output file exists check, ...
7
-
8
-
9
- ✔ ctix 'create' mode complete!
10
- transforming...
11
- ✓ 3 modules transformed.
12
- rendering chunks...
13
-
14
- [vite:dts] Start generate declaration files...
15
- dist/index.js 0.21 kB │ map: 0.09 kB
16
- dist/updater.js 1.39 kB │ map: 2.53 kB
17
- dist/createWindow.js 5.31 kB │ map: 10.92 kB
18
- [vite:dts] Declaration files built in 1832ms.
19
-
20
- ✓ built in 5.21s
21
- Updated package.json with exports
package/CHANGELOG.md DELETED
@@ -1,7 +0,0 @@
1
- # @kirill.konshin/electron
2
-
3
- ## 0.0.2
4
-
5
- ### Patch Changes
6
-
7
- - 63fdba8: Divided core to browser/node/worker-specific packages, CTIX upgrade, etc.
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -1,234 +0,0 @@
1
- import path from 'node:path';
2
- import https from 'node:https';
3
- import http from 'node:http';
4
- import fs from 'node:fs';
5
- import fsp from 'node:fs/promises';
6
- import url from 'node:url';
7
- import { Menu, app, BrowserWindow, shell, protocol, Rectangle } from 'electron';
8
- import defaultMenu from 'electron-default-menu';
9
- import Store from 'electron-store';
10
- import { checkForUpdates } from './updater.js';
11
-
12
- export const isDev: boolean = process.env['NODE_ENV'] === 'development';
13
- export const appPath: string = app.getAppPath();
14
-
15
- // See https://cs.chromium.org/chromium/src/net/base/net_error_list.h
16
- const FILE_NOT_FOUND = -6;
17
-
18
- const getPath = async (path_, file = '') => {
19
- try {
20
- const result = await fsp.stat(path_);
21
-
22
- if (result.isFile()) return path_;
23
-
24
- if (result.isDirectory()) return getPath(path.join(path_, `${file}.html`));
25
- } catch {
26
- /* empty */
27
- }
28
- };
29
-
30
- export function createWindow({
31
- width = 1000,
32
- height = 1000,
33
- disableSecurity = true,
34
- disableSecurityWarnings = true,
35
- quitOnClose = true,
36
- onOpen,
37
- onClose,
38
- localhostUrl = 'http://localhost:3000',
39
- productionUrl = '', // in this mode Electron acts as a browser for remote app
40
- webPath = path.resolve(appPath, 'web'), // must conform to what is in electron-builder.js files section
41
- useStaticInDev = false,
42
- updater = false,
43
- rememberBounds = true,
44
- }: {
45
- width?: number;
46
- height?: number;
47
- disableSecurity?: boolean;
48
- disableSecurityWarnings?: boolean;
49
- quitOnClose?: boolean;
50
- onOpen?: (win: BrowserWindow) => void;
51
- onClose?: (win: BrowserWindow) => void;
52
- localhostUrl?: string;
53
- productionUrl?: string;
54
- webPath?: string;
55
- useStaticInDev?: boolean;
56
- updater?: boolean;
57
- rememberBounds?: boolean;
58
- } = {}) {
59
- let mainWindow: BrowserWindow | null = null;
60
-
61
- console.log('[APP] Starting Electron', {
62
- isDev,
63
- appPath,
64
- useStaticInDev,
65
- localhostUrl,
66
- productionUrl,
67
- webPath,
68
- updater,
69
- rememberBounds,
70
- quitOnClose,
71
- disableSecurity,
72
- disableSecurityWarnings,
73
- });
74
-
75
- if (!productionUrl && !webPath) {
76
- throw new Error('productionUrl or webPath must be defined');
77
- }
78
-
79
- if (productionUrl && webPath) {
80
- throw new Error('productionUrl and webPath cannot be used together');
81
- }
82
-
83
- if (!localhostUrl) {
84
- throw new Error('localhostUrl must be defined');
85
- }
86
-
87
- const store = new Store<{ bounds: Rectangle }>({
88
- schema: {
89
- bounds: {
90
- type: 'object',
91
- properties: {
92
- // Docs: https://electronjs.org/docs/api/structures/rectangle
93
- height: { type: 'number' },
94
- width: { type: 'number' },
95
- x: { type: 'number' },
96
- y: { type: 'number' },
97
- },
98
- },
99
- },
100
- });
101
-
102
- if (disableSecurityWarnings) process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
103
- process.env['ELECTRON_ENABLE_LOGGING'] = 'true';
104
-
105
- process.on('SIGTERM', () => process.exit(0));
106
- process.on('SIGINT', () => process.exit(0));
107
-
108
- const openDevTools = () => {
109
- if (!mainWindow) return;
110
- mainWindow.setSize(width + 800, height);
111
- mainWindow.center();
112
- mainWindow.webContents.openDevTools();
113
- };
114
-
115
- const createWindow = async () => {
116
- mainWindow = new BrowserWindow({
117
- width,
118
- height,
119
- icon: path.resolve(appPath, 'assets/icon.png'),
120
- webPreferences: {
121
- nodeIntegration: false, // is default value after Electron v5
122
- contextIsolation: true, // protect against prototype pollution
123
- webSecurity: !disableSecurity,
124
- devTools: true,
125
- },
126
- ...(rememberBounds ? store.get('bounds') : {}),
127
- });
128
-
129
- mainWindow.on('move', () => rememberBounds && mainWindow && store.set('bounds', mainWindow.getBounds()));
130
-
131
- mainWindow.once('ready-to-show', () => isDev && openDevTools());
132
-
133
- // Static interceptor
134
-
135
- let interceptor: (() => void) | null = null;
136
-
137
- if (webPath && (!isDev || useStaticInDev)) {
138
- console.log(`[APP] Static Server Enabled, ${localhostUrl} will be intercepted to ${webPath}`);
139
-
140
- //TODO https://localhost:3000
141
- // @see https://github.com/sindresorhus/electron-serve/blob/main/index.js
142
- protocol.interceptStreamProtocol('http', (request, callback) => {
143
- if (request.url.startsWith(localhostUrl)) {
144
- let fileUrl = url.parse(request.url, false).pathname;
145
-
146
- if (!fileUrl) return callback({ error: FILE_NOT_FOUND });
147
-
148
- if (fileUrl === '/') fileUrl = 'index.html';
149
-
150
- const filePath = path.join(webPath, fileUrl);
151
-
152
- const relativePath = path.relative(webPath, fileUrl);
153
-
154
- const isSafe = !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
155
-
156
- if (!isSafe && !isDev) return callback({ error: FILE_NOT_FOUND });
157
-
158
- // const finalPath = await getPath(filePath, options.file);
159
- // const fileExtension = path.extname(filePath);
160
-
161
- console.log('[APP] Static Server', fileUrl, '->', filePath);
162
-
163
- // return {path: path.join(webPath, fileUrl)};
164
- callback(fs.createReadStream(filePath));
165
-
166
- return true;
167
- }
168
-
169
- // return {url: request.url};
170
- (request.url.startsWith('https') ? https : http).get(request.url, callback);
171
-
172
- return true;
173
- });
174
-
175
- interceptor = () => protocol.uninterceptProtocol('http');
176
- }
177
-
178
- mainWindow.on('closed', () => {
179
- interceptor?.();
180
- onClose?.(mainWindow as never);
181
- mainWindow = null;
182
- interceptor = null;
183
- });
184
-
185
- // External URLs
186
-
187
- mainWindow.webContents.setWindowOpenHandler(({ url }) => {
188
- shell.openExternal(url).catch((e) => console.error(e));
189
- return { action: 'deny' };
190
- });
191
-
192
- // Menu
193
-
194
- const menu = defaultMenu(app, shell);
195
-
196
- if (updater) {
197
- (menu.at(-1)!.submenu as any).push(
198
- { type: 'separator' },
199
- {
200
- label: 'Check For Updates',
201
- click: checkForUpdates,
202
- },
203
- );
204
- }
205
-
206
- Menu.setApplicationMenu(Menu.buildFromTemplate(menu)); //TODO onMenu
207
-
208
- // Should be last, after all listeners and menu
209
-
210
- await app.whenReady();
211
-
212
- onOpen?.(mainWindow);
213
-
214
- if (!onOpen && localhostUrl) {
215
- await mainWindow.loadURL(productionUrl && !isDev ? productionUrl : `${localhostUrl}/`);
216
- }
217
-
218
- console.log('[APP] Main Window Open');
219
- };
220
-
221
- app.on('ready', createWindow);
222
-
223
- app.on('window-all-closed', () => {
224
- if (process.platform !== 'darwin' || quitOnClose) app.quit();
225
- });
226
-
227
- app.on('activate', () => BrowserWindow.getAllWindows().length === 0 && !mainWindow && createWindow());
228
-
229
- return {
230
- get mainWindow(): BrowserWindow | null {
231
- return mainWindow;
232
- },
233
- };
234
- }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './createWindow';
2
- export * from './updater';
package/src/updater.ts DELETED
@@ -1,53 +0,0 @@
1
- // https://github.com/electron-userland/electron-builder/blob/docs-deprecated/encapsulated%20manual%20update%20via%20menu.js
2
- import { dialog } from 'electron';
3
- import { autoUpdater } from 'electron-updater';
4
-
5
- let updateButton;
6
-
7
- autoUpdater.autoDownload = false;
8
-
9
- autoUpdater.on('error', (error) => {
10
- dialog.showErrorBox('Error: ', !error ? 'unknown' : (error.stack || error).toString());
11
- });
12
-
13
- autoUpdater.on('update-available', async () => {
14
- const { response } = await dialog.showMessageBox({
15
- type: 'info',
16
- title: 'Found Updates',
17
- message: 'Found updates, do you want update now?',
18
- buttons: ['Yes', 'No'],
19
- });
20
-
21
- updateButton.enabled = true;
22
- updateButton = null;
23
-
24
- if (response === 0) await autoUpdater.downloadUpdate();
25
- });
26
-
27
- autoUpdater.on('update-not-available', async () => {
28
- try {
29
- await dialog.showMessageBox({
30
- title: 'No Updates',
31
- message: 'Current version is up-to-date.',
32
- });
33
- } catch (e) {
34
- dialog.showErrorBox('Error: ', e.toString());
35
- }
36
- updateButton.enabled = true;
37
- updateButton = null;
38
- });
39
-
40
- autoUpdater.on('update-downloaded', async () => {
41
- await dialog.showMessageBox({
42
- title: 'Install Update',
43
- message: 'Update downloaded, application will quit for update...',
44
- });
45
-
46
- autoUpdater.quitAndInstall();
47
- });
48
-
49
- export function checkForUpdates(menuItem: any): void {
50
- updateButton = menuItem;
51
- updateButton.enabled = false;
52
- autoUpdater.checkForUpdates().catch((e) => console.error('Update error', e));
53
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../utils-private/tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist",
6
- "declarationDir": "dist"
7
- },
8
- "include": ["src"],
9
- "exclude": []
10
- }
package/turbo.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "$schema": "https://turbo.build/schema.json",
3
- "extends": ["//"],
4
- "tasks": {
5
- "build": {
6
- "dependsOn": ["^build"],
7
- "outputs": ["src/**/*/index.ts", "package.json", "dist/**/*"]
8
- }
9
- }
10
- }
package/vite.config.ts DELETED
@@ -1,2 +0,0 @@
1
- import config from '../utils-private/vite.config';
2
- export default config;