pake-cli 3.2.0-beta15 → 3.2.12
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/dist/cli.js +177 -173
- package/dist/dev.js +295 -280
- package/dist/dev.js.map +1 -1
- package/package.json +6 -8
- package/src-tauri/.cargo/config.toml +4 -8
- package/src-tauri/.pake/pake.json +4 -4
- package/src-tauri/.pake/tauri.conf.json +5 -5
- package/src-tauri/.pake/tauri.linux.conf.json +1 -4
- package/src-tauri/.pake/tauri.macos.conf.json +3 -3
- package/src-tauri/src/app/window.rs +1 -5
- package/src-tauri/tauri.linux.conf.json +1 -4
package/dist/dev.js
CHANGED
|
@@ -4,13 +4,14 @@ import chalk from 'chalk';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import { dir } from 'tmp-promise';
|
|
7
|
-
import {
|
|
7
|
+
import { fileTypeFromBuffer } from 'file-type';
|
|
8
|
+
import icongen from 'icon-gen';
|
|
9
|
+
import sharp from 'sharp';
|
|
8
10
|
import crypto from 'crypto';
|
|
9
11
|
import prompts from 'prompts';
|
|
10
12
|
import ora from 'ora';
|
|
11
|
-
import {
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
12
14
|
import * as psl from 'psl';
|
|
13
|
-
import icongen from 'icon-gen';
|
|
14
15
|
import { execa, execaSync } from 'execa';
|
|
15
16
|
import dns from 'dns';
|
|
16
17
|
import http from 'http';
|
|
@@ -68,17 +69,6 @@ const logger = {
|
|
|
68
69
|
},
|
|
69
70
|
};
|
|
70
71
|
|
|
71
|
-
// Convert the current module URL to a file path
|
|
72
|
-
const currentModulePath = fileURLToPath(import.meta.url);
|
|
73
|
-
// Resolve the parent directory of the current module
|
|
74
|
-
const npmDirectory = path.join(path.dirname(currentModulePath), '..');
|
|
75
|
-
const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri', '.pake');
|
|
76
|
-
|
|
77
|
-
const { platform: platform$2 } = process;
|
|
78
|
-
const IS_MAC = platform$2 === 'darwin';
|
|
79
|
-
const IS_WIN = platform$2 === 'win32';
|
|
80
|
-
const IS_LINUX = platform$2 === 'linux';
|
|
81
|
-
|
|
82
72
|
// Generates an identifier based on the given URL.
|
|
83
73
|
function getIdentifier(url) {
|
|
84
74
|
const postFixHash = crypto
|
|
@@ -112,66 +102,94 @@ function getSpinner(text) {
|
|
|
112
102
|
}).start();
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
//
|
|
116
|
-
|
|
105
|
+
// Convert the current module URL to a file path
|
|
106
|
+
const currentModulePath = fileURLToPath(import.meta.url);
|
|
107
|
+
// Resolve the parent directory of the current module
|
|
108
|
+
const npmDirectory = path.join(path.dirname(currentModulePath), '..');
|
|
109
|
+
const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri', '.pake');
|
|
110
|
+
|
|
111
|
+
const { platform: platform$2 } = process;
|
|
112
|
+
const IS_MAC = platform$2 === 'darwin';
|
|
113
|
+
const IS_WIN = platform$2 === 'win32';
|
|
114
|
+
const IS_LINUX = platform$2 === 'linux';
|
|
115
|
+
|
|
116
|
+
// Constants
|
|
117
|
+
const ICON_CONFIG = {
|
|
118
|
+
minFileSize: 100,
|
|
119
|
+
downloadTimeout: 10000,
|
|
120
|
+
supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp'],
|
|
121
|
+
whiteBackground: { r: 255, g: 255, b: 255 },
|
|
122
|
+
};
|
|
123
|
+
// API Configuration
|
|
124
|
+
const API_TOKENS = {
|
|
125
|
+
// cspell:disable-next-line
|
|
126
|
+
logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
|
|
127
|
+
// cspell:disable-next-line
|
|
128
|
+
brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Adds white background to transparent icons only
|
|
132
|
+
*/
|
|
133
|
+
async function preprocessIcon(inputPath) {
|
|
117
134
|
try {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
135
|
+
const metadata = await sharp(inputPath).metadata();
|
|
136
|
+
if (metadata.channels !== 4)
|
|
137
|
+
return inputPath; // No transparency
|
|
138
|
+
const { path: tempDir } = await dir();
|
|
139
|
+
const outputPath = path.join(tempDir, 'icon-with-background.png');
|
|
140
|
+
await sharp({
|
|
141
|
+
create: {
|
|
142
|
+
width: metadata.width || 512,
|
|
143
|
+
height: metadata.height || 512,
|
|
144
|
+
channels: 3,
|
|
145
|
+
background: ICON_CONFIG.whiteBackground,
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
.composite([{ input: inputPath }])
|
|
149
|
+
.png()
|
|
150
|
+
.toFile(outputPath);
|
|
151
|
+
return outputPath;
|
|
128
152
|
}
|
|
129
153
|
catch (error) {
|
|
130
|
-
|
|
154
|
+
logger.warn(`Failed to add background to icon: ${error.message}`);
|
|
155
|
+
return inputPath;
|
|
131
156
|
}
|
|
132
157
|
}
|
|
133
|
-
|
|
134
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Converts icon to platform-specific format
|
|
160
|
+
*/
|
|
135
161
|
async function convertIconFormat(inputPath, appName) {
|
|
136
162
|
try {
|
|
163
|
+
if (!(await fsExtra.pathExists(inputPath)))
|
|
164
|
+
return null;
|
|
137
165
|
const { path: outputDir } = await dir();
|
|
138
166
|
const platformOutputDir = path.join(outputDir, 'converted-icons');
|
|
139
167
|
await fsExtra.ensureDir(platformOutputDir);
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
? `${appName.toLowerCase()}_512.png`
|
|
146
|
-
: `${appName.toLowerCase()}.icns`;
|
|
147
|
-
const outputPath = path.join(platformOutputDir, outputFileName);
|
|
148
|
-
// Convert using icon-gen
|
|
149
|
-
if (requiredFormat === 'icns') {
|
|
150
|
-
await icongen(inputPath, platformOutputDir, {
|
|
151
|
-
report: false,
|
|
152
|
-
icns: {
|
|
153
|
-
name: appName.toLowerCase(),
|
|
154
|
-
sizes: [16, 32, 64, 128, 256, 512, 1024]
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
else if (requiredFormat === 'ico') {
|
|
159
|
-
await icongen(inputPath, platformOutputDir, {
|
|
168
|
+
const processedInputPath = await preprocessIcon(inputPath);
|
|
169
|
+
const iconName = appName.toLowerCase();
|
|
170
|
+
// Generate platform-specific format
|
|
171
|
+
if (IS_WIN) {
|
|
172
|
+
await icongen(processedInputPath, platformOutputDir, {
|
|
160
173
|
report: false,
|
|
161
|
-
ico: {
|
|
162
|
-
name: `${appName.toLowerCase()}_256`,
|
|
163
|
-
sizes: [16, 24, 32, 48, 64, 128, 256]
|
|
164
|
-
}
|
|
174
|
+
ico: { name: `${iconName}_256`, sizes: [256] },
|
|
165
175
|
});
|
|
176
|
+
return path.join(platformOutputDir, `${iconName}_256.ico`);
|
|
166
177
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
await fsExtra.copy(
|
|
178
|
+
if (IS_LINUX) {
|
|
179
|
+
const outputPath = path.join(platformOutputDir, `${iconName}_512.png`);
|
|
180
|
+
await fsExtra.copy(processedInputPath, outputPath);
|
|
181
|
+
return outputPath;
|
|
170
182
|
}
|
|
171
|
-
|
|
183
|
+
// macOS
|
|
184
|
+
await icongen(processedInputPath, platformOutputDir, {
|
|
185
|
+
report: false,
|
|
186
|
+
icns: { name: iconName, sizes: [16, 32, 64, 128, 256, 512, 1024] },
|
|
187
|
+
});
|
|
188
|
+
const outputPath = path.join(platformOutputDir, `${iconName}.icns`);
|
|
189
|
+
return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
|
|
172
190
|
}
|
|
173
191
|
catch (error) {
|
|
174
|
-
logger.warn(
|
|
192
|
+
logger.warn(`Icon format conversion failed: ${error.message}`);
|
|
175
193
|
return null;
|
|
176
194
|
}
|
|
177
195
|
}
|
|
@@ -180,118 +198,169 @@ async function handleIcon(options, url) {
|
|
|
180
198
|
if (options.icon.startsWith('http')) {
|
|
181
199
|
return downloadIcon(options.icon);
|
|
182
200
|
}
|
|
183
|
-
|
|
184
|
-
return path.resolve(options.icon);
|
|
185
|
-
}
|
|
201
|
+
return path.resolve(options.icon);
|
|
186
202
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
// Try to get favicon from website if URL is provided
|
|
204
|
+
if (url && url.startsWith('http') && options.name) {
|
|
205
|
+
const faviconPath = await tryGetFavicon(url, options.name);
|
|
206
|
+
if (faviconPath)
|
|
207
|
+
return faviconPath;
|
|
208
|
+
}
|
|
209
|
+
logger.info('✼ No icon provided, using default icon.');
|
|
210
|
+
// For Windows, ensure we have proper fallback handling
|
|
211
|
+
if (IS_WIN) {
|
|
212
|
+
const defaultIcoPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
|
|
213
|
+
const defaultPngPath = path.join(npmDirectory, 'src-tauri/png/icon_512.png');
|
|
214
|
+
// First try default ico
|
|
215
|
+
if (await fsExtra.pathExists(defaultIcoPath)) {
|
|
216
|
+
return defaultIcoPath;
|
|
217
|
+
}
|
|
218
|
+
// If ico doesn't exist, try to convert from png
|
|
219
|
+
if (await fsExtra.pathExists(defaultPngPath)) {
|
|
220
|
+
logger.info('✼ Default ico not found, converting from png...');
|
|
221
|
+
try {
|
|
222
|
+
const convertedPath = await convertIconFormat(defaultPngPath, 'icon');
|
|
223
|
+
if (convertedPath && (await fsExtra.pathExists(convertedPath))) {
|
|
224
|
+
return convertedPath;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
logger.warn(`Failed to convert default png to ico: ${error.message}`);
|
|
193
229
|
}
|
|
194
230
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
231
|
+
// Last resort: return png path if it exists (Windows can handle png in some cases)
|
|
232
|
+
if (await fsExtra.pathExists(defaultPngPath)) {
|
|
233
|
+
logger.warn('✼ Using png as fallback for Windows (may cause issues).');
|
|
234
|
+
return defaultPngPath;
|
|
235
|
+
}
|
|
236
|
+
// If nothing exists, let the error bubble up
|
|
237
|
+
throw new Error('No default icon found for Windows build');
|
|
202
238
|
}
|
|
239
|
+
const iconPath = IS_LINUX
|
|
240
|
+
? 'src-tauri/png/icon_512.png'
|
|
241
|
+
: 'src-tauri/icons/icon.icns';
|
|
242
|
+
return path.join(npmDirectory, iconPath);
|
|
203
243
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Generates icon service URLs for a domain
|
|
246
|
+
*/
|
|
247
|
+
function generateIconServiceUrls(domain) {
|
|
248
|
+
const logoDevUrls = API_TOKENS.logoDev
|
|
249
|
+
.sort(() => Math.random() - 0.5)
|
|
250
|
+
.map((token) => `https://img.logo.dev/${domain}?token=${token}&format=png&size=256`);
|
|
251
|
+
const brandfetchUrls = API_TOKENS.brandfetch
|
|
252
|
+
.sort(() => Math.random() - 0.5)
|
|
253
|
+
.map((key) => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
|
|
254
|
+
return [
|
|
255
|
+
...logoDevUrls,
|
|
256
|
+
...brandfetchUrls,
|
|
213
257
|
`https://logo.clearbit.com/${domain}?size=256`,
|
|
214
258
|
`https://logo.uplead.com/${domain}`,
|
|
215
|
-
// Google's reliable service with larger size
|
|
216
259
|
`https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
|
|
217
|
-
// Other favicon services
|
|
218
260
|
`https://favicon.is/${domain}`,
|
|
219
261
|
`https://icons.duckduckgo.com/ip3/${domain}.ico`,
|
|
220
262
|
`https://icon.horse/icon/${domain}`,
|
|
221
|
-
// Direct favicon checks
|
|
222
263
|
`https://${domain}/favicon.ico`,
|
|
223
264
|
`https://www.${domain}/favicon.ico`,
|
|
224
265
|
`https://${domain}/apple-touch-icon.png`,
|
|
225
266
|
`https://${domain}/apple-touch-icon-precomposed.png`,
|
|
226
267
|
];
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Attempts to fetch favicon from website
|
|
271
|
+
*/
|
|
272
|
+
async function tryGetFavicon(url, appName) {
|
|
273
|
+
try {
|
|
274
|
+
const domain = new URL(url).hostname;
|
|
275
|
+
const spinner = getSpinner(`Fetching icon from ${domain}...`);
|
|
276
|
+
const serviceUrls = generateIconServiceUrls(domain);
|
|
277
|
+
// Use shorter timeout for CI environments
|
|
278
|
+
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
279
|
+
const downloadTimeout = isCI ? 5000 : ICON_CONFIG.downloadTimeout;
|
|
280
|
+
for (const serviceUrl of serviceUrls) {
|
|
281
|
+
try {
|
|
282
|
+
const faviconPath = await downloadIcon(serviceUrl, false, downloadTimeout);
|
|
283
|
+
if (!faviconPath)
|
|
284
|
+
continue;
|
|
233
285
|
const convertedPath = await convertIconFormat(faviconPath, appName);
|
|
234
286
|
if (convertedPath) {
|
|
235
|
-
spinner.succeed(chalk.green(
|
|
287
|
+
spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
|
|
236
288
|
return convertedPath;
|
|
237
289
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
// Log specific errors in CI for debugging
|
|
293
|
+
if (isCI) {
|
|
294
|
+
logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
|
|
241
295
|
}
|
|
296
|
+
continue;
|
|
242
297
|
}
|
|
243
298
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
299
|
+
spinner.warn(`✼ No favicon found for ${domain}. Using default.`);
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
logger.warn(`Failed to fetch favicon: ${error.message}`);
|
|
304
|
+
return null;
|
|
248
305
|
}
|
|
249
|
-
spinner.fail(chalk.yellow(`No favicon found for ${domain}, using default icon.`));
|
|
250
|
-
return null;
|
|
251
306
|
}
|
|
252
|
-
|
|
253
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Downloads icon from URL
|
|
309
|
+
*/
|
|
310
|
+
async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
|
|
254
311
|
try {
|
|
255
|
-
const
|
|
312
|
+
const response = await axios.get(iconUrl, {
|
|
256
313
|
responseType: 'arraybuffer',
|
|
257
|
-
timeout:
|
|
314
|
+
timeout: customTimeout || ICON_CONFIG.downloadTimeout,
|
|
258
315
|
});
|
|
259
|
-
const iconData =
|
|
260
|
-
if (!iconData || iconData.byteLength <
|
|
261
|
-
// Skip very small responses (likely error pages)
|
|
316
|
+
const iconData = response.data;
|
|
317
|
+
if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
|
|
262
318
|
return null;
|
|
263
|
-
}
|
|
264
319
|
const fileDetails = await fileTypeFromBuffer(iconData);
|
|
265
|
-
if (!fileDetails ||
|
|
266
|
-
|
|
320
|
+
if (!fileDetails ||
|
|
321
|
+
!ICON_CONFIG.supportedFormats.includes(fileDetails.ext)) {
|
|
267
322
|
return null;
|
|
268
323
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (
|
|
273
|
-
|
|
274
|
-
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, iconData);
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
await fsExtra.outputFile(iconPath, iconData);
|
|
278
|
-
}
|
|
279
|
-
await fsExtra.outputFile(iconPath, iconData);
|
|
280
|
-
if (spinner) {
|
|
281
|
-
spinner.succeed(chalk.green('Icon downloaded successfully!'));
|
|
324
|
+
return await saveIconFile(iconData, fileDetails.ext);
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
if (showSpinner && !(error.response?.status === 404)) {
|
|
328
|
+
throw error;
|
|
282
329
|
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Saves icon file to temporary location
|
|
335
|
+
*/
|
|
336
|
+
async function saveIconFile(iconData, extension) {
|
|
337
|
+
const buffer = Buffer.from(iconData);
|
|
338
|
+
if (IS_LINUX) {
|
|
339
|
+
const iconPath = 'png/linux_temp.png';
|
|
340
|
+
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
|
|
283
341
|
return iconPath;
|
|
284
342
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
343
|
+
const { path: tempPath } = await dir();
|
|
344
|
+
const iconPath = `${tempPath}/icon.${extension}`;
|
|
345
|
+
await fsExtra.outputFile(iconPath, buffer);
|
|
346
|
+
return iconPath;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Extracts the domain from a given URL.
|
|
350
|
+
function getDomain(inputUrl) {
|
|
351
|
+
try {
|
|
352
|
+
const url = new URL(inputUrl);
|
|
353
|
+
// Use PSL to parse domain names.
|
|
354
|
+
const parsed = psl.parse(url.hostname);
|
|
355
|
+
// If domain is available, split it and return the SLD.
|
|
356
|
+
if ('domain' in parsed && parsed.domain) {
|
|
357
|
+
return parsed.domain.split('.')[0];
|
|
288
358
|
}
|
|
289
|
-
|
|
359
|
+
else {
|
|
290
360
|
return null;
|
|
291
361
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
295
364
|
return null;
|
|
296
365
|
}
|
|
297
366
|
}
|
|
@@ -346,136 +415,13 @@ async function handleOptions(options, url) {
|
|
|
346
415
|
return appOptions;
|
|
347
416
|
}
|
|
348
417
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
height: 780,
|
|
357
|
-
resizable: true,
|
|
358
|
-
always_on_top: false,
|
|
359
|
-
dark_mode: false,
|
|
360
|
-
activation_shortcut: "",
|
|
361
|
-
disabled_web_shortcuts: false,
|
|
362
|
-
hide_on_close: true,
|
|
363
|
-
incognito: false
|
|
364
|
-
}
|
|
365
|
-
];
|
|
366
|
-
var user_agent = {
|
|
367
|
-
macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15",
|
|
368
|
-
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
|
|
369
|
-
windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
|
|
370
|
-
};
|
|
371
|
-
var system_tray = {
|
|
372
|
-
macos: false,
|
|
373
|
-
linux: true,
|
|
374
|
-
windows: true
|
|
375
|
-
};
|
|
376
|
-
var system_tray_path = "icons/icon.png";
|
|
377
|
-
var inject = [
|
|
378
|
-
];
|
|
379
|
-
var proxy_url = "";
|
|
380
|
-
var pakeConf = {
|
|
381
|
-
windows: windows,
|
|
382
|
-
user_agent: user_agent,
|
|
383
|
-
system_tray: system_tray,
|
|
384
|
-
system_tray_path: system_tray_path,
|
|
385
|
-
inject: inject,
|
|
386
|
-
proxy_url: proxy_url
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
var productName$1 = "Weekly";
|
|
390
|
-
var identifier = "com.pake.weekly";
|
|
391
|
-
var version = "1.0.0";
|
|
392
|
-
var app = {
|
|
393
|
-
withGlobalTauri: true,
|
|
394
|
-
trayIcon: {
|
|
395
|
-
iconPath: "png/weekly_512.png",
|
|
396
|
-
iconAsTemplate: false,
|
|
397
|
-
id: "pake-tray"
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
|
-
var build = {
|
|
401
|
-
frontendDist: "../dist"
|
|
402
|
-
};
|
|
403
|
-
var CommonConf = {
|
|
404
|
-
productName: productName$1,
|
|
405
|
-
identifier: identifier,
|
|
406
|
-
version: version,
|
|
407
|
-
app: app,
|
|
408
|
-
build: build
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
var bundle$2 = {
|
|
412
|
-
icon: [
|
|
413
|
-
"png/weekly_256.ico",
|
|
414
|
-
"png/weekly_32.ico"
|
|
415
|
-
],
|
|
416
|
-
active: true,
|
|
417
|
-
resources: [
|
|
418
|
-
"png/weekly_32.ico"
|
|
419
|
-
],
|
|
420
|
-
targets: [
|
|
421
|
-
"msi"
|
|
422
|
-
],
|
|
423
|
-
windows: {
|
|
424
|
-
digestAlgorithm: "sha256",
|
|
425
|
-
wix: {
|
|
426
|
-
language: [
|
|
427
|
-
"en-US"
|
|
428
|
-
],
|
|
429
|
-
template: "assets/main.wxs"
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
var WinConf = {
|
|
434
|
-
bundle: bundle$2
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
var bundle$1 = {
|
|
438
|
-
icon: [
|
|
439
|
-
"icons/weekly.icns"
|
|
440
|
-
],
|
|
441
|
-
active: true,
|
|
442
|
-
macOS: {
|
|
443
|
-
},
|
|
444
|
-
targets: [
|
|
445
|
-
"dmg"
|
|
446
|
-
]
|
|
447
|
-
};
|
|
448
|
-
var MacConf = {
|
|
449
|
-
bundle: bundle$1
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
var productName = "weekly";
|
|
453
|
-
var bundle = {
|
|
454
|
-
icon: [
|
|
455
|
-
"png/weekly_512.png"
|
|
456
|
-
],
|
|
457
|
-
active: true,
|
|
458
|
-
linux: {
|
|
459
|
-
deb: {
|
|
460
|
-
depends: [
|
|
461
|
-
"curl",
|
|
462
|
-
"wget"
|
|
463
|
-
],
|
|
464
|
-
files: {
|
|
465
|
-
"/usr/share/applications/com-pake-weekly.desktop": "assets/com-pake-weekly.desktop"
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
},
|
|
469
|
-
targets: [
|
|
470
|
-
"deb",
|
|
471
|
-
"appimage"
|
|
472
|
-
]
|
|
473
|
-
};
|
|
474
|
-
var LinuxConf = {
|
|
475
|
-
productName: productName,
|
|
476
|
-
bundle: bundle
|
|
477
|
-
};
|
|
478
|
-
|
|
418
|
+
// Load configs from npm package directory, not from project source
|
|
419
|
+
const tauriSrcDir = path.join(npmDirectory, 'src-tauri');
|
|
420
|
+
const pakeConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'pake.json'));
|
|
421
|
+
const CommonConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.conf.json'));
|
|
422
|
+
const WinConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.windows.conf.json'));
|
|
423
|
+
const MacConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.macos.conf.json'));
|
|
424
|
+
const LinuxConf = fsExtra.readJSONSync(path.join(tauriSrcDir, 'tauri.linux.conf.json'));
|
|
479
425
|
const platformConfigs = {
|
|
480
426
|
win32: WinConf,
|
|
481
427
|
darwin: MacConf,
|
|
@@ -497,13 +443,14 @@ let tauriConfig = {
|
|
|
497
443
|
pake: pakeConf,
|
|
498
444
|
};
|
|
499
445
|
|
|
500
|
-
async function shellExec(command, timeout = 300000) {
|
|
446
|
+
async function shellExec(command, timeout = 300000, env) {
|
|
501
447
|
try {
|
|
502
448
|
const { exitCode } = await execa(command, {
|
|
503
449
|
cwd: npmDirectory,
|
|
504
|
-
stdio: 'inherit',
|
|
450
|
+
stdio: ['inherit', 'pipe', 'inherit'], // Hide stdout verbose, keep stderr
|
|
505
451
|
shell: true,
|
|
506
452
|
timeout,
|
|
453
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
507
454
|
});
|
|
508
455
|
return exitCode;
|
|
509
456
|
}
|
|
@@ -572,11 +519,11 @@ async function installRust() {
|
|
|
572
519
|
const spinner = getSpinner('Downloading Rust...');
|
|
573
520
|
try {
|
|
574
521
|
await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
|
|
575
|
-
spinner.succeed(chalk.green('Rust installed successfully!'));
|
|
522
|
+
spinner.succeed(chalk.green('✔ Rust installed successfully!'));
|
|
576
523
|
}
|
|
577
524
|
catch (error) {
|
|
578
|
-
|
|
579
|
-
|
|
525
|
+
spinner.fail(chalk.red('✕ Rust installation failed!'));
|
|
526
|
+
console.error(error.message);
|
|
580
527
|
process.exit(1);
|
|
581
528
|
}
|
|
582
529
|
}
|
|
@@ -689,7 +636,33 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
689
636
|
tauriConf.pake.system_tray[currentPlatform] = showSystemTray;
|
|
690
637
|
// Processing targets are currently only open to Linux.
|
|
691
638
|
if (platform === 'linux') {
|
|
639
|
+
// Remove hardcoded desktop files and regenerate with correct app name
|
|
692
640
|
delete tauriConf.bundle.linux.deb.files;
|
|
641
|
+
// Generate correct desktop file configuration
|
|
642
|
+
const appNameLower = name.toLowerCase();
|
|
643
|
+
const identifier = `com.pake.${appNameLower}`;
|
|
644
|
+
const desktopFileName = `${identifier}.desktop`;
|
|
645
|
+
// Create desktop file content
|
|
646
|
+
const desktopContent = `[Desktop Entry]
|
|
647
|
+
Version=1.0
|
|
648
|
+
Type=Application
|
|
649
|
+
Name=${name}
|
|
650
|
+
Comment=${name}
|
|
651
|
+
Exec=${appNameLower}
|
|
652
|
+
Icon=${appNameLower}
|
|
653
|
+
Categories=Network;WebBrowser;
|
|
654
|
+
MimeType=text/html;text/xml;application/xhtml_xml;
|
|
655
|
+
StartupNotify=true
|
|
656
|
+
`;
|
|
657
|
+
// Write desktop file to assets directory
|
|
658
|
+
const assetsDir = path.join(npmDirectory, 'src-tauri/assets');
|
|
659
|
+
const desktopFilePath = path.join(assetsDir, desktopFileName);
|
|
660
|
+
await fsExtra.ensureDir(assetsDir);
|
|
661
|
+
await fsExtra.writeFile(desktopFilePath, desktopContent);
|
|
662
|
+
// Set up desktop file in bundle configuration
|
|
663
|
+
tauriConf.bundle.linux.deb.files = {
|
|
664
|
+
[`/usr/share/applications/${desktopFileName}`]: `assets/${desktopFileName}`,
|
|
665
|
+
};
|
|
693
666
|
const validTargets = ['deb', 'appimage', 'rpm'];
|
|
694
667
|
if (validTargets.includes(options.targets)) {
|
|
695
668
|
tauriConf.bundle.targets = [options.targets];
|
|
@@ -794,7 +767,6 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
794
767
|
};
|
|
795
768
|
const configPath = path.join(tauriConfigDirectory, platformConfigPaths[platform]);
|
|
796
769
|
const bundleConf = { bundle: tauriConf.bundle };
|
|
797
|
-
console.log('pakeConfig', tauriConf.pake);
|
|
798
770
|
await fsExtra.outputJSON(configPath, bundleConf, { spaces: 4 });
|
|
799
771
|
const pakeConfigPath = path.join(tauriConfigDirectory, 'pake.json');
|
|
800
772
|
await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
|
|
@@ -812,6 +784,21 @@ class BaseBuilder {
|
|
|
812
784
|
constructor(options) {
|
|
813
785
|
this.options = options;
|
|
814
786
|
}
|
|
787
|
+
getBuildEnvironment() {
|
|
788
|
+
return IS_MAC
|
|
789
|
+
? {
|
|
790
|
+
CFLAGS: '-fno-modules',
|
|
791
|
+
CXXFLAGS: '-fno-modules',
|
|
792
|
+
MACOSX_DEPLOYMENT_TARGET: '14.0',
|
|
793
|
+
}
|
|
794
|
+
: undefined;
|
|
795
|
+
}
|
|
796
|
+
getInstallTimeout() {
|
|
797
|
+
return process.platform === 'win32' ? 600000 : 300000;
|
|
798
|
+
}
|
|
799
|
+
getBuildTimeout() {
|
|
800
|
+
return 900000; // 15 minutes for all builds
|
|
801
|
+
}
|
|
815
802
|
async prepare() {
|
|
816
803
|
const tauriSrcPath = path.join(npmDirectory, 'src-tauri');
|
|
817
804
|
const tauriTargetPath = path.join(tauriSrcPath, 'target');
|
|
@@ -839,21 +826,22 @@ class BaseBuilder {
|
|
|
839
826
|
const rustProjectDir = path.join(tauriSrcPath, '.cargo');
|
|
840
827
|
const projectConf = path.join(rustProjectDir, 'config.toml');
|
|
841
828
|
await fsExtra.ensureDir(rustProjectDir);
|
|
842
|
-
//
|
|
829
|
+
// 统一使用npm,简单可靠
|
|
843
830
|
const packageManager = 'npm';
|
|
844
831
|
const registryOption = isChina
|
|
845
832
|
? ' --registry=https://registry.npmmirror.com'
|
|
846
833
|
: '';
|
|
847
|
-
//
|
|
848
|
-
const timeout =
|
|
834
|
+
const legacyPeerDeps = ' --legacy-peer-deps'; // 解决dependency conflicts
|
|
835
|
+
const timeout = this.getInstallTimeout();
|
|
836
|
+
const buildEnv = this.getBuildEnvironment();
|
|
849
837
|
if (isChina) {
|
|
850
838
|
logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
|
|
851
839
|
const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
|
|
852
840
|
await fsExtra.copy(projectCnConf, projectConf);
|
|
853
|
-
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}`, timeout);
|
|
841
|
+
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${legacyPeerDeps} --silent`, timeout, buildEnv);
|
|
854
842
|
}
|
|
855
843
|
else {
|
|
856
|
-
await shellExec(`cd "${npmDirectory}" && ${packageManager} install`, timeout);
|
|
844
|
+
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${legacyPeerDeps} --silent`, timeout, buildEnv);
|
|
857
845
|
}
|
|
858
846
|
spinner.succeed(chalk.green('Package installed!'));
|
|
859
847
|
if (!tauriTargetPathExists) {
|
|
@@ -870,9 +858,14 @@ class BaseBuilder {
|
|
|
870
858
|
const { name } = this.options;
|
|
871
859
|
await mergeConfig(url, this.options, tauriConfig);
|
|
872
860
|
// Build app
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
await
|
|
861
|
+
const buildSpinner = getSpinner('Building app...');
|
|
862
|
+
// Let spinner run for a moment so user can see it, then stop before npm command
|
|
863
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
864
|
+
buildSpinner.stop();
|
|
865
|
+
// Show static message to keep the status visible
|
|
866
|
+
logger.warn('✸ Building app...');
|
|
867
|
+
const buildEnv = this.getBuildEnvironment();
|
|
868
|
+
await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`, this.getBuildTimeout(), buildEnv);
|
|
876
869
|
// Copy app
|
|
877
870
|
const fileName = this.getFileName();
|
|
878
871
|
const fileType = this.getFileType(target);
|
|
@@ -897,13 +890,18 @@ class BaseBuilder {
|
|
|
897
890
|
if (IS_MAC && this.options.targets === 'app') {
|
|
898
891
|
fullCommand += ' --bundles app';
|
|
899
892
|
}
|
|
893
|
+
// Add features
|
|
894
|
+
const features = ['cli-build'];
|
|
900
895
|
// Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+)
|
|
901
896
|
if (IS_MAC) {
|
|
902
897
|
const macOSVersion = this.getMacOSMajorVersion();
|
|
903
898
|
if (macOSVersion >= 23) {
|
|
904
|
-
|
|
899
|
+
features.push('macos-proxy');
|
|
905
900
|
}
|
|
906
901
|
}
|
|
902
|
+
if (features.length > 0) {
|
|
903
|
+
fullCommand += ` --features ${features.join(',')}`;
|
|
904
|
+
}
|
|
907
905
|
return fullCommand;
|
|
908
906
|
}
|
|
909
907
|
getMacOSMajorVersion() {
|
|
@@ -957,9 +955,26 @@ class MacBuilder extends BaseBuilder {
|
|
|
957
955
|
return `${name}_${tauriConfig.version}_${arch}`;
|
|
958
956
|
}
|
|
959
957
|
getBuildCommand() {
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
958
|
+
if (this.options.multiArch) {
|
|
959
|
+
const baseCommand = this.options.debug
|
|
960
|
+
? 'npm run tauri build -- --debug'
|
|
961
|
+
: 'npm run tauri build --';
|
|
962
|
+
// Use temporary config directory to avoid modifying source files
|
|
963
|
+
const configPath = path.join('src-tauri', '.pake', 'tauri.conf.json');
|
|
964
|
+
let fullCommand = `${baseCommand} --target universal-apple-darwin -c "${configPath}"`;
|
|
965
|
+
// Add features
|
|
966
|
+
const features = ['cli-build'];
|
|
967
|
+
// Add macos-proxy feature for modern macOS (Darwin 23+ = macOS 14+)
|
|
968
|
+
const macOSVersion = this.getMacOSMajorVersion();
|
|
969
|
+
if (macOSVersion >= 23) {
|
|
970
|
+
features.push('macos-proxy');
|
|
971
|
+
}
|
|
972
|
+
if (features.length > 0) {
|
|
973
|
+
fullCommand += ` --features ${features.join(',')}`;
|
|
974
|
+
}
|
|
975
|
+
return fullCommand;
|
|
976
|
+
}
|
|
977
|
+
return super.getBuildCommand();
|
|
963
978
|
}
|
|
964
979
|
getBasePath() {
|
|
965
980
|
return this.options.multiArch
|