ai-zero-token 2.0.1 → 2.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.
- package/CHANGELOG.md +20 -0
- package/README.md +13 -5
- package/README.zh-CN.md +13 -5
- package/admin-ui/dist/assets/InfoRow-0ULI9iI3.js +1 -0
- package/admin-ui/dist/assets/accounts-DymL4WIa.js +2 -0
- package/admin-ui/dist/assets/activity-D21-Xrc4.js +1 -0
- package/admin-ui/dist/assets/app-mark-nsRs4vo7.svg +8 -0
- package/admin-ui/dist/assets/circle-check-ZYtn9GqY.js +1 -0
- package/admin-ui/dist/assets/clock-3-BzDANsVk.js +1 -0
- package/admin-ui/dist/assets/docs-BRNWAMPw.css +1 -0
- package/admin-ui/dist/assets/docs-DtO-AOWU.js +1735 -0
- package/admin-ui/dist/assets/earth-DFdZaQIi.js +1 -0
- package/admin-ui/dist/assets/image-bed-yIVQ4dKs.js +1 -0
- package/admin-ui/dist/assets/index-By4r-wy3.css +1 -0
- package/admin-ui/dist/assets/index-DRe-tByu.js +10 -0
- package/admin-ui/dist/assets/jsx-runtime-DqpGtLhh.js +1 -0
- package/admin-ui/dist/assets/launch-CQXYrl-h.js +1 -0
- package/admin-ui/dist/assets/logs-awABDg1C.js +1 -0
- package/admin-ui/dist/assets/network-detect-sSrnwZqf.js +1 -0
- package/admin-ui/dist/assets/overview-BbSON0Jl.js +1 -0
- package/admin-ui/dist/assets/profiles-DMOjJORP.js +1 -0
- package/admin-ui/dist/assets/refresh-cw-CAAH2rqe.js +1 -0
- package/admin-ui/dist/assets/search-B2hz41D3.js +1 -0
- package/admin-ui/dist/assets/server-BrjJPb9D.js +1 -0
- package/admin-ui/dist/assets/settings-DvRiHS7i.js +1 -0
- package/admin-ui/dist/assets/tester-CftPgRE9.js +3 -0
- package/admin-ui/dist/assets/upload-CwXb7Q1b.js +1 -0
- package/admin-ui/dist/assets/zap-B4_oDbCp.js +1 -0
- package/admin-ui/dist/index.html +5 -3
- package/build/icon.icns +0 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon.svg +8 -0
- package/build/mac-install-guide.txt +25 -0
- package/dist/core/context.js +3 -0
- package/dist/core/providers/http-client.js +11 -4
- package/dist/core/services/auth-service.js +88 -12
- package/dist/core/services/config-service.js +87 -23
- package/dist/core/services/github-image-bed-service.js +264 -0
- package/dist/core/services/network-detect-service.js +189 -74
- package/dist/core/services/version-service.js +1 -1
- package/dist/core/store/github-image-bed-history-store.js +68 -0
- package/dist/core/store/github-image-bed-store.js +52 -0
- package/dist/core/store/profile-store.js +73 -32
- package/dist/core/store/settings-store.js +14 -0
- package/dist/desktop/main.js +158 -6
- package/dist/server/app.js +168 -26
- package/dist/server/index.js +41 -15
- package/docs/DESKTOP_RELEASE.md +35 -3
- package/docs/PRODUCT_UPDATE_DESKTOP_TOOLBOX.md +2 -2
- package/package.json +34 -2
- package/admin-ui/dist/assets/app-mark-Gd2QnHMO.svg +0 -9
- package/admin-ui/dist/assets/index-DNzR8XR7.css +0 -1
- package/admin-ui/dist/assets/index-DZMegNPs.js +0 -1745
- package/dist/server/admin-page.js +0 -4586
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ensureStateMigrated, getStateDir } from "./state-paths.js";
|
|
5
|
+
function createEmptyStore() {
|
|
6
|
+
return {
|
|
7
|
+
version: 1,
|
|
8
|
+
github: {
|
|
9
|
+
token: ""
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
async function loadGithubImageBedStore() {
|
|
14
|
+
try {
|
|
15
|
+
await ensureStateMigrated();
|
|
16
|
+
const raw = await fs.readFile(getGithubImageBedStorePath(), "utf8");
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
return {
|
|
19
|
+
version: 1,
|
|
20
|
+
github: {
|
|
21
|
+
token: typeof parsed.github?.token === "string" ? parsed.github.token.trim() : ""
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
} catch {
|
|
25
|
+
return createEmptyStore();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function saveGithubImageBedStore(store) {
|
|
29
|
+
await ensureStateMigrated();
|
|
30
|
+
await fs.mkdir(getStateDir(), { recursive: true });
|
|
31
|
+
await fs.writeFile(getGithubImageBedStorePath(), `${JSON.stringify(store, null, 2)}
|
|
32
|
+
`, "utf8");
|
|
33
|
+
}
|
|
34
|
+
async function updateGithubImageBedToken(token) {
|
|
35
|
+
const store = await loadGithubImageBedStore();
|
|
36
|
+
store.github.token = token.trim();
|
|
37
|
+
await saveGithubImageBedStore(store);
|
|
38
|
+
return store;
|
|
39
|
+
}
|
|
40
|
+
async function clearGithubImageBedStore() {
|
|
41
|
+
await saveGithubImageBedStore(createEmptyStore());
|
|
42
|
+
}
|
|
43
|
+
function getGithubImageBedStorePath() {
|
|
44
|
+
return path.join(getStateDir(), "github-image-bed.json");
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
clearGithubImageBedStore,
|
|
48
|
+
getGithubImageBedStorePath,
|
|
49
|
+
loadGithubImageBedStore,
|
|
50
|
+
saveGithubImageBedStore,
|
|
51
|
+
updateGithubImageBedToken
|
|
52
|
+
};
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getStorePath
|
|
7
7
|
} from "./state-paths.js";
|
|
8
8
|
const PROFILE_CLAIM_PATH = "https://api.openai.com/profile";
|
|
9
|
+
let storeMutationQueue = Promise.resolve();
|
|
9
10
|
function createEmptyStore() {
|
|
10
11
|
return {
|
|
11
12
|
version: 1,
|
|
@@ -73,36 +74,50 @@ async function saveStore(store) {
|
|
|
73
74
|
await fs.writeFile(getStorePath(), `${JSON.stringify(store, null, 2)}
|
|
74
75
|
`, "utf8");
|
|
75
76
|
}
|
|
77
|
+
async function withStoreMutation(operation) {
|
|
78
|
+
const run = storeMutationQueue.then(operation, operation);
|
|
79
|
+
storeMutationQueue = run.then(
|
|
80
|
+
() => void 0,
|
|
81
|
+
() => void 0
|
|
82
|
+
);
|
|
83
|
+
return run;
|
|
84
|
+
}
|
|
76
85
|
async function saveProfile(profile) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
await withStoreMutation(async () => {
|
|
87
|
+
const store = await loadStore();
|
|
88
|
+
store.profiles[profile.profileId] = profile;
|
|
89
|
+
store.activeProfileId = profile.profileId;
|
|
90
|
+
await saveStore(store);
|
|
91
|
+
});
|
|
81
92
|
}
|
|
82
93
|
async function updateProfile(profileId, updater) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
return withStoreMutation(async () => {
|
|
95
|
+
const store = await loadStore();
|
|
96
|
+
const profile = store.profiles[profileId];
|
|
97
|
+
if (!profile) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const updated = updater(profile);
|
|
101
|
+
store.profiles[profileId] = updated;
|
|
102
|
+
await saveStore(store);
|
|
103
|
+
return updated;
|
|
104
|
+
});
|
|
92
105
|
}
|
|
93
106
|
async function listProfiles() {
|
|
94
107
|
const store = await loadStore();
|
|
95
108
|
return Object.values(store.profiles);
|
|
96
109
|
}
|
|
97
110
|
async function setActiveProfile(profileId) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
return withStoreMutation(async () => {
|
|
112
|
+
const store = await loadStore();
|
|
113
|
+
const profile = store.profiles[profileId];
|
|
114
|
+
if (!profile) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
store.activeProfileId = profileId;
|
|
118
|
+
await saveStore(store);
|
|
119
|
+
return profile;
|
|
120
|
+
});
|
|
106
121
|
}
|
|
107
122
|
async function getActiveProfile() {
|
|
108
123
|
const store = await loadStore();
|
|
@@ -114,19 +129,44 @@ async function getActiveProfile() {
|
|
|
114
129
|
return first ?? null;
|
|
115
130
|
}
|
|
116
131
|
async function removeProfile(profileId) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
store.activeProfileId
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
return withStoreMutation(async () => {
|
|
133
|
+
const store = await loadStore();
|
|
134
|
+
if (!store.profiles[profileId]) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
delete store.profiles[profileId];
|
|
138
|
+
if (store.activeProfileId === profileId) {
|
|
139
|
+
store.activeProfileId = Object.keys(store.profiles)[0];
|
|
140
|
+
}
|
|
141
|
+
await saveStore(store);
|
|
142
|
+
return store.activeProfileId ? store.profiles[store.activeProfileId] ?? null : null;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async function removeProfiles(profileIds) {
|
|
146
|
+
return withStoreMutation(async () => {
|
|
147
|
+
const idSet = new Set(profileIds.map((id) => id.trim()).filter(Boolean));
|
|
148
|
+
if (idSet.size === 0) {
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
const store = await loadStore();
|
|
152
|
+
let removed = 0;
|
|
153
|
+
for (const profileId of idSet) {
|
|
154
|
+
if (store.profiles[profileId]) {
|
|
155
|
+
delete store.profiles[profileId];
|
|
156
|
+
removed += 1;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (store.activeProfileId && !store.profiles[store.activeProfileId]) {
|
|
160
|
+
store.activeProfileId = Object.keys(store.profiles)[0];
|
|
161
|
+
}
|
|
162
|
+
await saveStore(store);
|
|
163
|
+
return removed;
|
|
164
|
+
});
|
|
127
165
|
}
|
|
128
166
|
async function clearStore() {
|
|
129
|
-
await
|
|
167
|
+
await withStoreMutation(async () => {
|
|
168
|
+
await fs.rm(getStateDir(), { recursive: true, force: true });
|
|
169
|
+
});
|
|
130
170
|
}
|
|
131
171
|
export {
|
|
132
172
|
clearStore,
|
|
@@ -136,6 +176,7 @@ export {
|
|
|
136
176
|
listProfiles,
|
|
137
177
|
loadStore,
|
|
138
178
|
removeProfile,
|
|
179
|
+
removeProfiles,
|
|
139
180
|
saveProfile,
|
|
140
181
|
saveStore,
|
|
141
182
|
setActiveProfile,
|
|
@@ -18,6 +18,9 @@ function createDefaultSettings() {
|
|
|
18
18
|
autoSwitch: {
|
|
19
19
|
enabled: false
|
|
20
20
|
},
|
|
21
|
+
runtime: {
|
|
22
|
+
quotaSyncConcurrency: 16
|
|
23
|
+
},
|
|
21
24
|
server: {
|
|
22
25
|
host: "0.0.0.0",
|
|
23
26
|
port: 8787
|
|
@@ -42,6 +45,9 @@ async function loadSettings() {
|
|
|
42
45
|
autoSwitch: {
|
|
43
46
|
enabled: parsed.autoSwitch?.enabled ?? defaults.autoSwitch.enabled
|
|
44
47
|
},
|
|
48
|
+
runtime: {
|
|
49
|
+
quotaSyncConcurrency: normalizeQuotaSyncConcurrency(parsed.runtime?.quotaSyncConcurrency, defaults.runtime.quotaSyncConcurrency)
|
|
50
|
+
},
|
|
45
51
|
server: {
|
|
46
52
|
host: parsed.server?.host ?? defaults.server.host,
|
|
47
53
|
port: parsed.server?.port ?? defaults.server.port
|
|
@@ -51,6 +57,13 @@ async function loadSettings() {
|
|
|
51
57
|
return createDefaultSettings();
|
|
52
58
|
}
|
|
53
59
|
}
|
|
60
|
+
function normalizeQuotaSyncConcurrency(value, fallback = 16) {
|
|
61
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : fallback;
|
|
62
|
+
if (!Number.isFinite(parsed)) {
|
|
63
|
+
return fallback;
|
|
64
|
+
}
|
|
65
|
+
return Math.min(32, Math.max(1, Math.trunc(parsed)));
|
|
66
|
+
}
|
|
54
67
|
async function saveSettings(settings) {
|
|
55
68
|
await ensureStateMigrated();
|
|
56
69
|
await fs.mkdir(getStateDir(), { recursive: true });
|
|
@@ -61,5 +74,6 @@ export {
|
|
|
61
74
|
createDefaultSettings,
|
|
62
75
|
getSettingsPath,
|
|
63
76
|
loadSettings,
|
|
77
|
+
normalizeQuotaSyncConcurrency,
|
|
64
78
|
saveSettings
|
|
65
79
|
};
|
package/dist/desktop/main.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { app as electronApp, BrowserWindow, dialog, shell } from "electron";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { startServer } from "../server/index.js";
|
|
6
7
|
let gatewayServer = null;
|
|
7
8
|
let mainWindow = null;
|
|
8
9
|
let isQuitting = false;
|
|
10
|
+
let isRestarting = false;
|
|
11
|
+
let currentGatewayUrl = null;
|
|
12
|
+
let currentAdminUrl = null;
|
|
9
13
|
const desktopDir = path.dirname(fileURLToPath(import.meta.url));
|
|
10
14
|
const appIconPath = path.resolve(desktopDir, "../../build/icon.png");
|
|
15
|
+
const startupPageUrl = buildStartupPageUrl("\u6B63\u5728\u542F\u52A8\u672C\u5730\u7F51\u5173");
|
|
11
16
|
electronApp.setName("AI Zero Token");
|
|
12
17
|
function createBrowserUrl(host, port) {
|
|
13
18
|
if (host === "0.0.0.0" || host === "::") {
|
|
@@ -28,11 +33,143 @@ function resolveAdminUrl(gatewayUrl) {
|
|
|
28
33
|
const devUrl = process.env.AZT_ADMIN_UI_DEV_URL?.trim();
|
|
29
34
|
return devUrl || gatewayUrl;
|
|
30
35
|
}
|
|
36
|
+
function resolvePreferredGatewayParams() {
|
|
37
|
+
const devUrl = process.env.AZT_DEV_GATEWAY_URL?.trim();
|
|
38
|
+
if (!devUrl) {
|
|
39
|
+
return void 0;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const parsed = new URL(devUrl);
|
|
43
|
+
const host = parsed.hostname || void 0;
|
|
44
|
+
const port = Number.parseInt(parsed.port, 10);
|
|
45
|
+
return {
|
|
46
|
+
host,
|
|
47
|
+
port: Number.isFinite(port) ? port : void 0
|
|
48
|
+
};
|
|
49
|
+
} catch {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function isAllowedAppUrl(targetUrl) {
|
|
54
|
+
return Boolean(currentAdminUrl && isGatewayUrl(targetUrl, currentAdminUrl) || currentGatewayUrl && isGatewayUrl(targetUrl, currentGatewayUrl));
|
|
55
|
+
}
|
|
56
|
+
async function restartGateway() {
|
|
57
|
+
if (isRestarting) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
isRestarting = true;
|
|
61
|
+
try {
|
|
62
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
63
|
+
await mainWindow.loadURL(buildStartupPageUrl("\u6B63\u5728\u91CD\u542F\u672C\u5730\u7F51\u5173"));
|
|
64
|
+
}
|
|
65
|
+
await closeGatewayServer().catch((error) => {
|
|
66
|
+
console.error("[desktop:gateway:restart-close]", error);
|
|
67
|
+
});
|
|
68
|
+
const server = await ensureGatewayServer();
|
|
69
|
+
const gatewayUrl = createBrowserUrl(server.host, server.port);
|
|
70
|
+
const adminUrl = resolveAdminUrl(gatewayUrl);
|
|
71
|
+
currentGatewayUrl = gatewayUrl;
|
|
72
|
+
currentAdminUrl = adminUrl;
|
|
73
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
74
|
+
await mainWindow.loadURL(adminUrl);
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
console.error("[desktop:gateway:restart]", error);
|
|
79
|
+
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
80
|
+
await mainWindow.loadURL(buildStartupPageUrl(`\u7F51\u5173\u91CD\u542F\u5931\u8D25\uFF1A${message}`)).catch(() => void 0);
|
|
81
|
+
}
|
|
82
|
+
dialog.showErrorBox("AI Zero Token \u7F51\u5173\u91CD\u542F\u5931\u8D25", message);
|
|
83
|
+
} finally {
|
|
84
|
+
isRestarting = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function buildStartupPageUrl(subtitle) {
|
|
88
|
+
const iconUrl = `data:image/png;base64,${readFileSync(appIconPath).toString("base64")}`;
|
|
89
|
+
const html = `<!doctype html>
|
|
90
|
+
<html lang="zh-CN">
|
|
91
|
+
<head>
|
|
92
|
+
<meta charset="UTF-8" />
|
|
93
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
94
|
+
<style>
|
|
95
|
+
:root { color-scheme: dark; }
|
|
96
|
+
html, body {
|
|
97
|
+
width: 100%;
|
|
98
|
+
height: 100%;
|
|
99
|
+
margin: 0;
|
|
100
|
+
background: #050816;
|
|
101
|
+
color: #f8fafc;
|
|
102
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
103
|
+
}
|
|
104
|
+
body {
|
|
105
|
+
display: grid;
|
|
106
|
+
place-items: center;
|
|
107
|
+
}
|
|
108
|
+
.wrap {
|
|
109
|
+
display: grid;
|
|
110
|
+
gap: 18px;
|
|
111
|
+
justify-items: center;
|
|
112
|
+
}
|
|
113
|
+
.mark {
|
|
114
|
+
width: 96px;
|
|
115
|
+
height: 96px;
|
|
116
|
+
border-radius: 24px;
|
|
117
|
+
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.35);
|
|
118
|
+
}
|
|
119
|
+
.title {
|
|
120
|
+
font-size: 22px;
|
|
121
|
+
font-weight: 700;
|
|
122
|
+
letter-spacing: 0;
|
|
123
|
+
}
|
|
124
|
+
.sub {
|
|
125
|
+
font-size: 14px;
|
|
126
|
+
color: rgba(248, 250, 252, 0.66);
|
|
127
|
+
}
|
|
128
|
+
.bar {
|
|
129
|
+
width: 220px;
|
|
130
|
+
height: 4px;
|
|
131
|
+
border-radius: 999px;
|
|
132
|
+
background: rgba(255,255,255,0.08);
|
|
133
|
+
overflow: hidden;
|
|
134
|
+
}
|
|
135
|
+
.bar::after {
|
|
136
|
+
content: "";
|
|
137
|
+
display: block;
|
|
138
|
+
width: 45%;
|
|
139
|
+
height: 100%;
|
|
140
|
+
border-radius: inherit;
|
|
141
|
+
background: linear-gradient(90deg, #93c5fd 0%, #66f0c0 55%, #f97316 100%);
|
|
142
|
+
animation: load 1.2s ease-in-out infinite;
|
|
143
|
+
}
|
|
144
|
+
@keyframes load {
|
|
145
|
+
0% { transform: translateX(-30%); }
|
|
146
|
+
50% { transform: translateX(80%); }
|
|
147
|
+
100% { transform: translateX(-30%); }
|
|
148
|
+
}
|
|
149
|
+
</style>
|
|
150
|
+
</head>
|
|
151
|
+
<body>
|
|
152
|
+
<div class="wrap">
|
|
153
|
+
<img class="mark" src="${iconUrl}" alt="" />
|
|
154
|
+
<div class="title">AI Zero Token</div>
|
|
155
|
+
<div class="sub">${escapeHtml(subtitle)}</div>
|
|
156
|
+
<div class="bar" aria-hidden="true"></div>
|
|
157
|
+
</div>
|
|
158
|
+
</body>
|
|
159
|
+
</html>`;
|
|
160
|
+
return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
|
|
161
|
+
}
|
|
162
|
+
function escapeHtml(value) {
|
|
163
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
164
|
+
}
|
|
31
165
|
async function ensureGatewayServer() {
|
|
32
166
|
if (gatewayServer) {
|
|
33
167
|
return gatewayServer;
|
|
34
168
|
}
|
|
35
|
-
gatewayServer = await startServer(
|
|
169
|
+
gatewayServer = await startServer({
|
|
170
|
+
...resolvePreferredGatewayParams(),
|
|
171
|
+
onRestart: restartGateway
|
|
172
|
+
});
|
|
36
173
|
const adminUrl = createBrowserUrl(gatewayServer.host, gatewayServer.port);
|
|
37
174
|
console.log("AI Zero Token desktop gateway started.");
|
|
38
175
|
console.log(`admin: ${adminUrl}`);
|
|
@@ -41,9 +178,6 @@ async function ensureGatewayServer() {
|
|
|
41
178
|
return gatewayServer;
|
|
42
179
|
}
|
|
43
180
|
async function createMainWindow() {
|
|
44
|
-
const server = await ensureGatewayServer();
|
|
45
|
-
const gatewayUrl = createBrowserUrl(server.host, server.port);
|
|
46
|
-
const adminUrl = resolveAdminUrl(gatewayUrl);
|
|
47
181
|
mainWindow = new BrowserWindow({
|
|
48
182
|
width: 1440,
|
|
49
183
|
height: 960,
|
|
@@ -51,7 +185,8 @@ async function createMainWindow() {
|
|
|
51
185
|
minHeight: 720,
|
|
52
186
|
title: "AI Zero Token",
|
|
53
187
|
icon: appIconPath,
|
|
54
|
-
backgroundColor: "#
|
|
188
|
+
backgroundColor: "#050816",
|
|
189
|
+
show: false,
|
|
55
190
|
webPreferences: {
|
|
56
191
|
contextIsolation: true,
|
|
57
192
|
nodeIntegration: false,
|
|
@@ -63,7 +198,7 @@ async function createMainWindow() {
|
|
|
63
198
|
return { action: "deny" };
|
|
64
199
|
});
|
|
65
200
|
mainWindow.webContents.on("will-navigate", (event, url) => {
|
|
66
|
-
if (
|
|
201
|
+
if (isAllowedAppUrl(url)) {
|
|
67
202
|
return;
|
|
68
203
|
}
|
|
69
204
|
event.preventDefault();
|
|
@@ -72,6 +207,23 @@ async function createMainWindow() {
|
|
|
72
207
|
mainWindow.on("closed", () => {
|
|
73
208
|
mainWindow = null;
|
|
74
209
|
});
|
|
210
|
+
mainWindow.once("ready-to-show", () => {
|
|
211
|
+
if (mainWindow) {
|
|
212
|
+
mainWindow.show();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
await mainWindow.loadURL(startupPageUrl);
|
|
216
|
+
if (mainWindow && !mainWindow.isVisible()) {
|
|
217
|
+
mainWindow.show();
|
|
218
|
+
}
|
|
219
|
+
const server = await ensureGatewayServer();
|
|
220
|
+
if (!mainWindow) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const gatewayUrl = createBrowserUrl(server.host, server.port);
|
|
224
|
+
const adminUrl = resolveAdminUrl(gatewayUrl);
|
|
225
|
+
currentGatewayUrl = gatewayUrl;
|
|
226
|
+
currentAdminUrl = adminUrl;
|
|
75
227
|
await mainWindow.loadURL(adminUrl);
|
|
76
228
|
}
|
|
77
229
|
function focusMainWindow() {
|