🎨 Continue using npm
This commit is contained in:
17
.github/workflows/pake_build_single_app.yaml
vendored
17
.github/workflows/pake_build_single_app.yaml
vendored
@@ -71,16 +71,11 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies (ubuntu only)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
@@ -108,13 +103,13 @@ jobs:
|
||||
NAME_ZH: ${{ inputs.name_zh }}
|
||||
URL: ${{ inputs.url }}
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm run build:config
|
||||
npm ci
|
||||
npm run build:config
|
||||
|
||||
- name: Build for Ubuntu
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pnpm run tauri build
|
||||
npm run tauri build
|
||||
mkdir -p output/linux
|
||||
mv src-tauri/target/release/bundle/deb/*.deb output/linux/${{inputs.title}}_`arch`.deb
|
||||
mv src-tauri/target/release/bundle/appimage/*.AppImage output/linux/"${{inputs.title}}"_`arch`.AppImage
|
||||
@@ -124,14 +119,14 @@ jobs:
|
||||
run: |
|
||||
rustup target add aarch64-apple-darwin
|
||||
rustup target add x86_64-apple-darwin
|
||||
pnpm run tauri build -- --target universal-apple-darwin
|
||||
npm run tauri build -- --target universal-apple-darwin
|
||||
mkdir -p output/macos
|
||||
mv src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg output/macos/"${{inputs.title}}".dmg
|
||||
|
||||
- name: Build for Windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
pnpm run tauri build -- --target x86_64-pc-windows-msvc
|
||||
npm run tauri build -- --target x86_64-pc-windows-msvc
|
||||
New-Item -Path "output\windows" -ItemType Directory
|
||||
Move-Item -Path "src-tauri\target\x86_64-pc-windows-msvc\release\bundle\msi\*.msi" -Destination "output\windows\${{inputs.title}}_x64.msi"
|
||||
|
||||
|
||||
22
.github/workflows/quality-and-test.yml
vendored
22
.github/workflows/quality-and-test.yml
vendored
@@ -22,19 +22,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
cache: "pnpm"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
run: npm ci
|
||||
|
||||
- name: Check EditorConfig compliance
|
||||
uses: editorconfig-checker/action-editorconfig-checker@main
|
||||
@@ -94,16 +89,11 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install Rust (Ubuntu)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
@@ -134,13 +124,13 @@ jobs:
|
||||
version: 1.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
run: npm ci
|
||||
|
||||
- name: Build CLI
|
||||
run: pnpm run cli:build
|
||||
run: npm run cli:build
|
||||
|
||||
- name: Run CLI Test Suite
|
||||
run: pnpm test
|
||||
run: npm test
|
||||
env:
|
||||
CI: true
|
||||
NODE_ENV: test
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -33,11 +33,10 @@ RUN --mount=type=cache,target=/var/cache/apt \
|
||||
libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev \
|
||||
gnome-video-effects
|
||||
|
||||
# Install Node.js 20.x and pnpm
|
||||
# Install Node.js 22.x
|
||||
RUN --mount=type=cache,target=/var/cache/apt \
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
|
||||
apt-get update && apt-get install -y nodejs && \
|
||||
npm install -g pnpm
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
|
||||
apt-get update && apt-get install -y nodejs
|
||||
|
||||
# Copy project files
|
||||
COPY . /pake
|
||||
@@ -49,9 +48,9 @@ COPY --from=cargo-builder /cargo-cache/git /usr/local/cargo/git
|
||||
COPY --from=cargo-builder /cargo-cache/registry /usr/local/cargo/registry
|
||||
|
||||
# Install dependencies and build pake-cli
|
||||
RUN --mount=type=cache,target=/root/.pnpm \
|
||||
pnpm install --frozen-lockfile && \
|
||||
pnpm run cli:build
|
||||
RUN --mount=type=cache,target=/root/.npm \
|
||||
npm ci && \
|
||||
npm run cli:build
|
||||
|
||||
# Set up the entrypoint
|
||||
WORKDIR /output
|
||||
|
||||
49
bin/builders/BaseBuilder.ts
vendored
49
bin/builders/BaseBuilder.ts
vendored
@@ -21,6 +21,24 @@ export default abstract class BaseBuilder {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
private getBuildEnvironment() {
|
||||
return IS_MAC
|
||||
? {
|
||||
CFLAGS: '-fno-modules',
|
||||
CXXFLAGS: '-fno-modules',
|
||||
MACOSX_DEPLOYMENT_TARGET: '14.0',
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private getInstallTimeout(): number {
|
||||
return process.platform === 'win32' ? 600000 : 300000;
|
||||
}
|
||||
|
||||
private getBuildTimeout(): number {
|
||||
return 300000; // 5 minutes for build process
|
||||
}
|
||||
|
||||
async prepare() {
|
||||
const tauriSrcPath = path.join(npmDirectory, 'src-tauri');
|
||||
const tauriTargetPath = path.join(tauriSrcPath, 'target');
|
||||
@@ -52,27 +70,31 @@ export default abstract class BaseBuilder {
|
||||
const projectConf = path.join(rustProjectDir, 'config.toml');
|
||||
await fsExtra.ensureDir(rustProjectDir);
|
||||
|
||||
// For global CLI installation, always use npm
|
||||
// 统一使用npm,简单可靠
|
||||
const packageManager = 'npm';
|
||||
const registryOption = isChina
|
||||
? ' --registry=https://registry.npmmirror.com'
|
||||
: '';
|
||||
const legacyPeerDeps = ' --legacy-peer-deps'; // 解决dependency conflicts
|
||||
|
||||
// Windows环境下需要更长的超时时间
|
||||
const timeout = process.platform === 'win32' ? 600000 : 300000;
|
||||
const timeout = this.getInstallTimeout();
|
||||
|
||||
const buildEnv = this.getBuildEnvironment();
|
||||
|
||||
if (isChina) {
|
||||
logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
|
||||
const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
|
||||
await fsExtra.copy(projectCnConf, projectConf);
|
||||
await shellExec(
|
||||
`cd "${npmDirectory}" && ${packageManager} install${registryOption}`,
|
||||
`cd "${npmDirectory}" && ${packageManager} install${registryOption}${legacyPeerDeps} --silent`,
|
||||
timeout,
|
||||
buildEnv,
|
||||
);
|
||||
} else {
|
||||
await shellExec(
|
||||
`cd "${npmDirectory}" && ${packageManager} install`,
|
||||
`cd "${npmDirectory}" && ${packageManager} install${legacyPeerDeps} --silent`,
|
||||
timeout,
|
||||
buildEnv,
|
||||
);
|
||||
}
|
||||
spinner.succeed(chalk.green('Package installed!'));
|
||||
@@ -96,9 +118,20 @@ export default abstract class BaseBuilder {
|
||||
await mergeConfig(url, this.options, tauriConfig);
|
||||
|
||||
// Build app
|
||||
const spinner = getSpinner('Building app...');
|
||||
setTimeout(() => spinner.stop(), 3000);
|
||||
await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`);
|
||||
const buildSpinner = getSpinner('Building app...');
|
||||
// Let spinner run for a moment so user can see it, then stop before npm command
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
buildSpinner.stop();
|
||||
// Show static message to keep the status visible
|
||||
logger.warn('✸ Building app...');
|
||||
|
||||
const buildEnv = this.getBuildEnvironment();
|
||||
|
||||
await shellExec(
|
||||
`cd "${npmDirectory}" && ${this.getBuildCommand()}`,
|
||||
this.getBuildTimeout(),
|
||||
buildEnv,
|
||||
);
|
||||
|
||||
// Copy app
|
||||
const fileName = this.getFileName();
|
||||
|
||||
1
bin/cli.ts
vendored
1
bin/cli.ts
vendored
@@ -161,7 +161,6 @@ program
|
||||
}
|
||||
|
||||
const appOptions = await handleInputOptions(options, url);
|
||||
log.debug('PakeAppOptions', appOptions);
|
||||
|
||||
const builder = BuilderProvider.create(appOptions);
|
||||
await builder.prepare();
|
||||
|
||||
1
bin/helpers/merge.ts
vendored
1
bin/helpers/merge.ts
vendored
@@ -268,7 +268,6 @@ export async function mergeConfig(
|
||||
);
|
||||
|
||||
const bundleConf = { bundle: tauriConf.bundle };
|
||||
console.log('pakeConfig', tauriConf.pake);
|
||||
await fsExtra.outputJSON(configPath, bundleConf, { spaces: 4 });
|
||||
const pakeConfigPath = path.join(tauriConfigDirectory, 'pake.json');
|
||||
await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
|
||||
|
||||
6
bin/helpers/rust.ts
vendored
6
bin/helpers/rust.ts
vendored
@@ -21,10 +21,10 @@ export async function installRust() {
|
||||
await shellExec(
|
||||
IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac,
|
||||
);
|
||||
spinner.succeed(chalk.green('Rust installed successfully!'));
|
||||
spinner.succeed(chalk.green('✔ Rust installed successfully!'));
|
||||
} catch (error) {
|
||||
console.error('Error installing Rust:', error.message);
|
||||
spinner.fail(chalk.red('Rust installation failed!'));
|
||||
spinner.fail(chalk.red('✕ Rust installation failed!'));
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
260
bin/options/icon.ts
vendored
260
bin/options/icon.ts
vendored
@@ -3,71 +3,249 @@ import axios from 'axios';
|
||||
import fsExtra from 'fs-extra';
|
||||
import chalk from 'chalk';
|
||||
import { dir } from 'tmp-promise';
|
||||
import { fileTypeFromBuffer } from 'file-type';
|
||||
import icongen from 'icon-gen';
|
||||
import sharp from 'sharp';
|
||||
|
||||
import logger from './logger';
|
||||
import { getSpinner } from '@/utils/info';
|
||||
import { npmDirectory } from '@/utils/dir';
|
||||
import { IS_LINUX, IS_WIN } from '@/utils/platform';
|
||||
import { getSpinner } from '@/utils/info';
|
||||
import { fileTypeFromBuffer } from 'file-type';
|
||||
import { PakeAppOptions } from '@/types';
|
||||
|
||||
export async function handleIcon(options: PakeAppOptions) {
|
||||
// Constants
|
||||
const ICON_CONFIG = {
|
||||
minFileSize: 100,
|
||||
downloadTimeout: 10000,
|
||||
supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp'] as const,
|
||||
whiteBackground: { r: 255, g: 255, b: 255 },
|
||||
};
|
||||
|
||||
// API Configuration
|
||||
const API_TOKENS = {
|
||||
// cspell:disable-next-line
|
||||
logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
|
||||
// cspell:disable-next-line
|
||||
brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds white background to transparent icons only
|
||||
*/
|
||||
async function preprocessIcon(inputPath: string): Promise<string> {
|
||||
try {
|
||||
const metadata = await sharp(inputPath).metadata();
|
||||
if (metadata.channels !== 4) return inputPath; // No transparency
|
||||
|
||||
const { path: tempDir } = await dir();
|
||||
const outputPath = path.join(tempDir, 'icon-with-background.png');
|
||||
|
||||
await sharp({
|
||||
create: {
|
||||
width: metadata.width || 512,
|
||||
height: metadata.height || 512,
|
||||
channels: 3,
|
||||
background: ICON_CONFIG.whiteBackground,
|
||||
},
|
||||
})
|
||||
.composite([{ input: inputPath }])
|
||||
.png()
|
||||
.toFile(outputPath);
|
||||
|
||||
return outputPath;
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to add background to icon: ${error.message}`);
|
||||
return inputPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts icon to platform-specific format
|
||||
*/
|
||||
async function convertIconFormat(
|
||||
inputPath: string,
|
||||
appName: string,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
if (!(await fsExtra.pathExists(inputPath))) return null;
|
||||
|
||||
const { path: outputDir } = await dir();
|
||||
const platformOutputDir = path.join(outputDir, 'converted-icons');
|
||||
await fsExtra.ensureDir(platformOutputDir);
|
||||
|
||||
const processedInputPath = await preprocessIcon(inputPath);
|
||||
const iconName = appName.toLowerCase();
|
||||
|
||||
// Generate platform-specific format
|
||||
if (IS_WIN) {
|
||||
await icongen(processedInputPath, platformOutputDir, {
|
||||
report: false,
|
||||
ico: { name: `${iconName}_256`, sizes: [256] },
|
||||
});
|
||||
return path.join(platformOutputDir, `${iconName}_256.ico`);
|
||||
}
|
||||
|
||||
if (IS_LINUX) {
|
||||
const outputPath = path.join(platformOutputDir, `${iconName}_512.png`);
|
||||
await fsExtra.copy(processedInputPath, outputPath);
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
// macOS
|
||||
await icongen(processedInputPath, platformOutputDir, {
|
||||
report: false,
|
||||
icns: { name: iconName, sizes: [16, 32, 64, 128, 256, 512, 1024] },
|
||||
});
|
||||
const outputPath = path.join(platformOutputDir, `${iconName}.icns`);
|
||||
return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
|
||||
} catch (error) {
|
||||
logger.warn(`Icon format conversion failed: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleIcon(options: PakeAppOptions, url?: string) {
|
||||
if (options.icon) {
|
||||
if (options.icon.startsWith('http')) {
|
||||
return downloadIcon(options.icon);
|
||||
} else {
|
||||
return path.resolve(options.icon);
|
||||
}
|
||||
} else {
|
||||
logger.warn(
|
||||
'✼ No icon given, default in use. For a custom icon, use --icon option.',
|
||||
return path.resolve(options.icon);
|
||||
}
|
||||
|
||||
// Try to get favicon from website if URL is provided
|
||||
if (url && url.startsWith('http') && options.name) {
|
||||
const faviconPath = await tryGetFavicon(url, options.name);
|
||||
if (faviconPath) return faviconPath;
|
||||
}
|
||||
|
||||
logger.info('✼ No icon provided, using default icon.');
|
||||
const iconPath = IS_WIN
|
||||
? 'src-tauri/png/icon_256.ico'
|
||||
: IS_LINUX
|
||||
? 'src-tauri/png/icon_512.png'
|
||||
: 'src-tauri/icons/icon.icns';
|
||||
return path.join(npmDirectory, iconPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates icon service URLs for a domain
|
||||
*/
|
||||
function generateIconServiceUrls(domain: string): string[] {
|
||||
const logoDevUrls = API_TOKENS.logoDev
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.map(
|
||||
(token) =>
|
||||
`https://img.logo.dev/${domain}?token=${token}&format=png&size=256`,
|
||||
);
|
||||
const iconPath = IS_WIN
|
||||
? 'src-tauri/png/icon_256.ico'
|
||||
: IS_LINUX
|
||||
? 'src-tauri/png/icon_512.png'
|
||||
: 'src-tauri/icons/icon.icns';
|
||||
return path.join(npmDirectory, iconPath);
|
||||
|
||||
const brandfetchUrls = API_TOKENS.brandfetch
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.map((key) => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
|
||||
|
||||
return [
|
||||
...logoDevUrls,
|
||||
...brandfetchUrls,
|
||||
`https://logo.clearbit.com/${domain}?size=256`,
|
||||
`https://logo.uplead.com/${domain}`,
|
||||
`https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
|
||||
`https://favicon.is/${domain}`,
|
||||
`https://icons.duckduckgo.com/ip3/${domain}.ico`,
|
||||
`https://icon.horse/icon/${domain}`,
|
||||
`https://${domain}/favicon.ico`,
|
||||
`https://www.${domain}/favicon.ico`,
|
||||
`https://${domain}/apple-touch-icon.png`,
|
||||
`https://${domain}/apple-touch-icon-precomposed.png`,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to fetch favicon from website
|
||||
*/
|
||||
async function tryGetFavicon(
|
||||
url: string,
|
||||
appName: string,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const domain = new URL(url).hostname;
|
||||
const spinner = getSpinner(`Fetching icon from ${domain}...`);
|
||||
|
||||
const serviceUrls = generateIconServiceUrls(domain);
|
||||
|
||||
for (const serviceUrl of serviceUrls) {
|
||||
try {
|
||||
const faviconPath = await downloadIcon(serviceUrl, false);
|
||||
if (!faviconPath) continue;
|
||||
|
||||
const convertedPath = await convertIconFormat(faviconPath, appName);
|
||||
if (convertedPath) {
|
||||
spinner.succeed(
|
||||
chalk.green('Icon fetched and converted successfully!'),
|
||||
);
|
||||
return convertedPath;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
spinner.warn(`✼ No favicon found for ${domain}. Using default.`);
|
||||
return null;
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to fetch favicon: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function downloadIcon(iconUrl: string) {
|
||||
const spinner = getSpinner('Downloading icon...');
|
||||
/**
|
||||
* Downloads icon from URL
|
||||
*/
|
||||
export async function downloadIcon(
|
||||
iconUrl: string,
|
||||
showSpinner = true,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const iconResponse = await axios.get(iconUrl, {
|
||||
const response = await axios.get(iconUrl, {
|
||||
responseType: 'arraybuffer',
|
||||
timeout: ICON_CONFIG.downloadTimeout,
|
||||
});
|
||||
const iconData = await iconResponse.data;
|
||||
|
||||
if (!iconData) {
|
||||
return null;
|
||||
}
|
||||
const iconData = response.data;
|
||||
if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize) return null;
|
||||
|
||||
const fileDetails = await fileTypeFromBuffer(iconData);
|
||||
if (!fileDetails) {
|
||||
if (
|
||||
!fileDetails ||
|
||||
!ICON_CONFIG.supportedFormats.includes(fileDetails.ext as any)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { path: tempPath } = await dir();
|
||||
let iconPath = `${tempPath}/icon.${fileDetails.ext}`;
|
||||
// Fix this for linux
|
||||
if (IS_LINUX) {
|
||||
iconPath = 'png/linux_temp.png';
|
||||
await fsExtra.outputFile(
|
||||
`${npmDirectory}/src-tauri/${iconPath}`,
|
||||
iconData,
|
||||
);
|
||||
} else {
|
||||
await fsExtra.outputFile(iconPath, iconData);
|
||||
}
|
||||
await fsExtra.outputFile(iconPath, iconData);
|
||||
spinner.succeed(chalk.green('Icon downloaded successfully!'));
|
||||
return iconPath;
|
||||
return await saveIconFile(iconData, fileDetails.ext);
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Icon download failed!'));
|
||||
if (error.response && error.response.status === 404) {
|
||||
return null;
|
||||
if (showSpinner && !(error.response?.status === 404)) {
|
||||
throw error;
|
||||
}
|
||||
throw error;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves icon file to temporary location
|
||||
*/
|
||||
async function saveIconFile(
|
||||
iconData: ArrayBuffer,
|
||||
extension: string,
|
||||
): Promise<string> {
|
||||
const buffer = Buffer.from(iconData);
|
||||
|
||||
if (IS_LINUX) {
|
||||
const iconPath = 'png/linux_temp.png';
|
||||
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
const { path: tempPath } = await dir();
|
||||
const iconPath = `${tempPath}/icon.${extension}`;
|
||||
await fsExtra.outputFile(iconPath, buffer);
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
2
bin/options/index.ts
vendored
2
bin/options/index.ts
vendored
@@ -62,7 +62,7 @@ export default async function handleOptions(
|
||||
identifier: getIdentifier(url),
|
||||
};
|
||||
|
||||
appOptions.icon = await handleIcon(appOptions);
|
||||
appOptions.icon = await handleIcon(appOptions, url);
|
||||
|
||||
return appOptions;
|
||||
}
|
||||
|
||||
9
bin/utils/shell.ts
vendored
9
bin/utils/shell.ts
vendored
@@ -1,13 +1,18 @@
|
||||
import { execa } from 'execa';
|
||||
import { npmDirectory } from './dir';
|
||||
|
||||
export async function shellExec(command: string, timeout: number = 300000) {
|
||||
export async function shellExec(
|
||||
command: string,
|
||||
timeout: number = 300000,
|
||||
env?: Record<string, string>,
|
||||
) {
|
||||
try {
|
||||
const { exitCode } = await execa(command, {
|
||||
cwd: npmDirectory,
|
||||
stdio: 'inherit',
|
||||
stdio: ['inherit', 'pipe', 'inherit'], // Hide stdout verbose, keep stderr
|
||||
shell: true,
|
||||
timeout,
|
||||
env: env ? { ...process.env, ...env } : process.env,
|
||||
});
|
||||
return exitCode;
|
||||
} catch (error: any) {
|
||||
|
||||
296
dist/cli.js
vendored
296
dist/cli.js
vendored
@@ -17,10 +17,12 @@ import updateNotifier from 'update-notifier';
|
||||
import axios from 'axios';
|
||||
import { dir } from 'tmp-promise';
|
||||
import { fileTypeFromBuffer } from 'file-type';
|
||||
import icongen from 'icon-gen';
|
||||
import sharp from 'sharp';
|
||||
import * as psl from 'psl';
|
||||
|
||||
var name = "pake-cli";
|
||||
var version$1 = "3.2.0-beta11";
|
||||
var version$1 = "3.2.0-beta15";
|
||||
var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
|
||||
var engines = {
|
||||
node: ">=16.0.0"
|
||||
@@ -69,19 +71,20 @@ var type = "module";
|
||||
var exports = "./dist/cli.js";
|
||||
var license = "MIT";
|
||||
var dependencies = {
|
||||
"@tauri-apps/api": "^2.7.0",
|
||||
"@tauri-apps/cli": "^2.7.1",
|
||||
"@tauri-apps/api": "^2.8.0",
|
||||
"@tauri-apps/cli": "^2.8.1",
|
||||
axios: "^1.11.0",
|
||||
chalk: "^5.5.0",
|
||||
chalk: "^5.6.0",
|
||||
commander: "^11.1.0",
|
||||
execa: "^9.6.0",
|
||||
"file-type": "^18.7.0",
|
||||
"fs-extra": "^11.3.1",
|
||||
"icon-gen": "^5.0.0",
|
||||
loglevel: "^1.9.2",
|
||||
ora: "^8.2.0",
|
||||
"pake-cli": "file:.yalc/pake-cli",
|
||||
prompts: "^2.4.2",
|
||||
psl: "^1.15.0",
|
||||
sharp: "^0.33.5",
|
||||
"tmp-promise": "^3.0.3",
|
||||
"update-notifier": "^7.3.1"
|
||||
};
|
||||
@@ -92,16 +95,15 @@ var devDependencies = {
|
||||
"@rollup/plugin-replace": "^6.0.2",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^20.19.10",
|
||||
"@types/node": "^20.19.11",
|
||||
"@types/page-icon": "^0.3.6",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/psl": "^1.11.0",
|
||||
"@types/tmp": "^0.2.6",
|
||||
"@types/update-notifier": "^6.0.8",
|
||||
"app-root-path": "^3.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
prettier: "^3.4.2",
|
||||
rollup: "^4.46.2",
|
||||
prettier: "^3.6.2",
|
||||
rollup: "^4.46.3",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
tslib: "^2.8.1",
|
||||
typescript: "^5.9.2"
|
||||
@@ -319,13 +321,14 @@ const currentModulePath = fileURLToPath(import.meta.url);
|
||||
const npmDirectory = path.join(path.dirname(currentModulePath), '..');
|
||||
const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri', '.pake');
|
||||
|
||||
async function shellExec(command, timeout = 300000) {
|
||||
async function shellExec(command, timeout = 300000, env) {
|
||||
try {
|
||||
const { exitCode } = await execa(command, {
|
||||
cwd: npmDirectory,
|
||||
stdio: 'inherit',
|
||||
stdio: ['inherit', 'pipe', 'inherit'], // Hide stdout verbose, keep stderr
|
||||
shell: true,
|
||||
timeout,
|
||||
env: env ? { ...process.env, ...env } : process.env,
|
||||
});
|
||||
return exitCode;
|
||||
}
|
||||
@@ -412,11 +415,11 @@ async function installRust() {
|
||||
const spinner = getSpinner('Downloading Rust...');
|
||||
try {
|
||||
await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
|
||||
spinner.succeed(chalk.green('Rust installed successfully!'));
|
||||
spinner.succeed(chalk.green('✔ Rust installed successfully!'));
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error installing Rust:', error.message);
|
||||
spinner.fail(chalk.red('Rust installation failed!'));
|
||||
spinner.fail(chalk.red('✕ Rust installation failed!'));
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -634,7 +637,6 @@ async function mergeConfig(url, options, tauriConf) {
|
||||
};
|
||||
const configPath = path.join(tauriConfigDirectory, platformConfigPaths[platform]);
|
||||
const bundleConf = { bundle: tauriConf.bundle };
|
||||
console.log('pakeConfig', tauriConf.pake);
|
||||
await fsExtra.outputJSON(configPath, bundleConf, { spaces: 4 });
|
||||
const pakeConfigPath = path.join(tauriConfigDirectory, 'pake.json');
|
||||
await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
|
||||
@@ -648,6 +650,19 @@ class BaseBuilder {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
getBuildEnvironment() {
|
||||
return IS_MAC ? {
|
||||
'CFLAGS': '-fno-modules',
|
||||
'CXXFLAGS': '-fno-modules',
|
||||
'MACOSX_DEPLOYMENT_TARGET': '14.0'
|
||||
} : undefined;
|
||||
}
|
||||
getInstallTimeout() {
|
||||
return process.platform === 'win32' ? 600000 : 300000;
|
||||
}
|
||||
getBuildTimeout() {
|
||||
return 300000; // 5 minutes for build process
|
||||
}
|
||||
async prepare() {
|
||||
const tauriSrcPath = path.join(npmDirectory, 'src-tauri');
|
||||
const tauriTargetPath = path.join(tauriSrcPath, 'target');
|
||||
@@ -675,21 +690,20 @@ class BaseBuilder {
|
||||
const rustProjectDir = path.join(tauriSrcPath, '.cargo');
|
||||
const projectConf = path.join(rustProjectDir, 'config.toml');
|
||||
await fsExtra.ensureDir(rustProjectDir);
|
||||
// For global CLI installation, always use npm
|
||||
// 统一使用npm,简单可靠
|
||||
const packageManager = 'npm';
|
||||
const registryOption = isChina
|
||||
? ' --registry=https://registry.npmmirror.com'
|
||||
: '';
|
||||
// Windows环境下需要更长的超时时间
|
||||
const timeout = process.platform === 'win32' ? 600000 : 300000;
|
||||
const registryOption = isChina ? ' --registry=https://registry.npmmirror.com' : '';
|
||||
const legacyPeerDeps = ' --legacy-peer-deps'; // 解决dependency conflicts
|
||||
const timeout = this.getInstallTimeout();
|
||||
const buildEnv = this.getBuildEnvironment();
|
||||
if (isChina) {
|
||||
logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
|
||||
const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
|
||||
await fsExtra.copy(projectCnConf, projectConf);
|
||||
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}`, timeout);
|
||||
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${legacyPeerDeps} --silent`, timeout, buildEnv);
|
||||
}
|
||||
else {
|
||||
await shellExec(`cd "${npmDirectory}" && ${packageManager} install`, timeout);
|
||||
await shellExec(`cd "${npmDirectory}" && ${packageManager} install${legacyPeerDeps} --silent`, timeout, buildEnv);
|
||||
}
|
||||
spinner.succeed(chalk.green('Package installed!'));
|
||||
if (!tauriTargetPathExists) {
|
||||
@@ -706,9 +720,14 @@ class BaseBuilder {
|
||||
const { name } = this.options;
|
||||
await mergeConfig(url, this.options, tauriConfig);
|
||||
// Build app
|
||||
const spinner = getSpinner('Building app...');
|
||||
setTimeout(() => spinner.stop(), 3000);
|
||||
await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`);
|
||||
const buildSpinner = getSpinner('Building app...');
|
||||
// Let spinner run for a moment so user can see it, then stop before npm command
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
buildSpinner.stop();
|
||||
// Show static message to keep the status visible
|
||||
logger.warn('✸ Building app...');
|
||||
const buildEnv = this.getBuildEnvironment();
|
||||
await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`, this.getBuildTimeout(), buildEnv);
|
||||
// Copy app
|
||||
const fileName = this.getFileName();
|
||||
const fileType = this.getFileType(target);
|
||||
@@ -898,60 +917,202 @@ async function checkUpdateTips() {
|
||||
});
|
||||
}
|
||||
|
||||
async function handleIcon(options) {
|
||||
// Constants
|
||||
const ICON_CONFIG = {
|
||||
minFileSize: 100,
|
||||
downloadTimeout: 10000,
|
||||
supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp'],
|
||||
whiteBackground: { r: 255, g: 255, b: 255 },
|
||||
};
|
||||
// API Configuration
|
||||
const API_TOKENS = {
|
||||
// cspell:disable-next-line
|
||||
logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
|
||||
// cspell:disable-next-line
|
||||
brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
|
||||
};
|
||||
/**
|
||||
* Adds white background to transparent icons only
|
||||
*/
|
||||
async function preprocessIcon(inputPath) {
|
||||
try {
|
||||
const metadata = await sharp(inputPath).metadata();
|
||||
if (metadata.channels !== 4)
|
||||
return inputPath; // No transparency
|
||||
const { path: tempDir } = await dir();
|
||||
const outputPath = path.join(tempDir, 'icon-with-background.png');
|
||||
await sharp({
|
||||
create: {
|
||||
width: metadata.width || 512,
|
||||
height: metadata.height || 512,
|
||||
channels: 3,
|
||||
background: ICON_CONFIG.whiteBackground,
|
||||
},
|
||||
})
|
||||
.composite([{ input: inputPath }])
|
||||
.png()
|
||||
.toFile(outputPath);
|
||||
return outputPath;
|
||||
}
|
||||
catch (error) {
|
||||
logger.warn(`Failed to add background to icon: ${error.message}`);
|
||||
return inputPath;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Converts icon to platform-specific format
|
||||
*/
|
||||
async function convertIconFormat(inputPath, appName) {
|
||||
try {
|
||||
if (!(await fsExtra.pathExists(inputPath)))
|
||||
return null;
|
||||
const { path: outputDir } = await dir();
|
||||
const platformOutputDir = path.join(outputDir, 'converted-icons');
|
||||
await fsExtra.ensureDir(platformOutputDir);
|
||||
const processedInputPath = await preprocessIcon(inputPath);
|
||||
const iconName = appName.toLowerCase();
|
||||
// Generate platform-specific format
|
||||
if (IS_WIN) {
|
||||
await icongen(processedInputPath, platformOutputDir, {
|
||||
report: false,
|
||||
ico: { name: `${iconName}_256`, sizes: [256] },
|
||||
});
|
||||
return path.join(platformOutputDir, `${iconName}_256.ico`);
|
||||
}
|
||||
if (IS_LINUX) {
|
||||
const outputPath = path.join(platformOutputDir, `${iconName}_512.png`);
|
||||
await fsExtra.copy(processedInputPath, outputPath);
|
||||
return outputPath;
|
||||
}
|
||||
// macOS
|
||||
await icongen(processedInputPath, platformOutputDir, {
|
||||
report: false,
|
||||
icns: { name: iconName, sizes: [16, 32, 64, 128, 256, 512, 1024] },
|
||||
});
|
||||
const outputPath = path.join(platformOutputDir, `${iconName}.icns`);
|
||||
return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
|
||||
}
|
||||
catch (error) {
|
||||
logger.warn(`Icon format conversion failed: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async function handleIcon(options, url) {
|
||||
if (options.icon) {
|
||||
if (options.icon.startsWith('http')) {
|
||||
return downloadIcon(options.icon);
|
||||
}
|
||||
else {
|
||||
return path.resolve(options.icon);
|
||||
}
|
||||
return path.resolve(options.icon);
|
||||
}
|
||||
else {
|
||||
logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.');
|
||||
const iconPath = IS_WIN
|
||||
? 'src-tauri/png/icon_256.ico'
|
||||
: IS_LINUX
|
||||
? 'src-tauri/png/icon_512.png'
|
||||
: 'src-tauri/icons/icon.icns';
|
||||
return path.join(npmDirectory, iconPath);
|
||||
// Try to get favicon from website if URL is provided
|
||||
if (url && url.startsWith('http') && options.name) {
|
||||
const faviconPath = await tryGetFavicon(url, options.name);
|
||||
if (faviconPath)
|
||||
return faviconPath;
|
||||
}
|
||||
logger.info('✼ No icon provided, using default icon.');
|
||||
const iconPath = IS_WIN
|
||||
? 'src-tauri/png/icon_256.ico'
|
||||
: IS_LINUX
|
||||
? 'src-tauri/png/icon_512.png'
|
||||
: 'src-tauri/icons/icon.icns';
|
||||
return path.join(npmDirectory, iconPath);
|
||||
}
|
||||
async function downloadIcon(iconUrl) {
|
||||
const spinner = getSpinner('Downloading icon...');
|
||||
/**
|
||||
* Generates icon service URLs for a domain
|
||||
*/
|
||||
function generateIconServiceUrls(domain) {
|
||||
const logoDevUrls = API_TOKENS.logoDev
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.map(token => `https://img.logo.dev/${domain}?token=${token}&format=png&size=256`);
|
||||
const brandfetchUrls = API_TOKENS.brandfetch
|
||||
.sort(() => Math.random() - 0.5)
|
||||
.map(key => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
|
||||
return [
|
||||
...logoDevUrls,
|
||||
...brandfetchUrls,
|
||||
`https://logo.clearbit.com/${domain}?size=256`,
|
||||
`https://logo.uplead.com/${domain}`,
|
||||
`https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
|
||||
`https://favicon.is/${domain}`,
|
||||
`https://icons.duckduckgo.com/ip3/${domain}.ico`,
|
||||
`https://icon.horse/icon/${domain}`,
|
||||
`https://${domain}/favicon.ico`,
|
||||
`https://www.${domain}/favicon.ico`,
|
||||
`https://${domain}/apple-touch-icon.png`,
|
||||
`https://${domain}/apple-touch-icon-precomposed.png`,
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Attempts to fetch favicon from website
|
||||
*/
|
||||
async function tryGetFavicon(url, appName) {
|
||||
try {
|
||||
const iconResponse = await axios.get(iconUrl, {
|
||||
responseType: 'arraybuffer',
|
||||
});
|
||||
const iconData = await iconResponse.data;
|
||||
if (!iconData) {
|
||||
return null;
|
||||
const domain = new URL(url).hostname;
|
||||
const spinner = getSpinner(`Fetching icon from ${domain}...`);
|
||||
const serviceUrls = generateIconServiceUrls(domain);
|
||||
for (const serviceUrl of serviceUrls) {
|
||||
try {
|
||||
const faviconPath = await downloadIcon(serviceUrl, false);
|
||||
if (!faviconPath)
|
||||
continue;
|
||||
const convertedPath = await convertIconFormat(faviconPath, appName);
|
||||
if (convertedPath) {
|
||||
spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
|
||||
return convertedPath;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const fileDetails = await fileTypeFromBuffer(iconData);
|
||||
if (!fileDetails) {
|
||||
return null;
|
||||
}
|
||||
const { path: tempPath } = await dir();
|
||||
let iconPath = `${tempPath}/icon.${fileDetails.ext}`;
|
||||
// Fix this for linux
|
||||
if (IS_LINUX) {
|
||||
iconPath = 'png/linux_temp.png';
|
||||
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, iconData);
|
||||
}
|
||||
else {
|
||||
await fsExtra.outputFile(iconPath, iconData);
|
||||
}
|
||||
await fsExtra.outputFile(iconPath, iconData);
|
||||
spinner.succeed(chalk.green('Icon downloaded successfully!'));
|
||||
return iconPath;
|
||||
spinner.warn(`✼ No favicon found for ${domain}. Using default.`);
|
||||
return null;
|
||||
}
|
||||
catch (error) {
|
||||
spinner.fail(chalk.red('Icon download failed!'));
|
||||
if (error.response && error.response.status === 404) {
|
||||
logger.warn(`Failed to fetch favicon: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Downloads icon from URL
|
||||
*/
|
||||
async function downloadIcon(iconUrl, showSpinner = true) {
|
||||
try {
|
||||
const response = await axios.get(iconUrl, {
|
||||
responseType: 'arraybuffer',
|
||||
timeout: ICON_CONFIG.downloadTimeout,
|
||||
});
|
||||
const iconData = response.data;
|
||||
if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
|
||||
return null;
|
||||
const fileDetails = await fileTypeFromBuffer(iconData);
|
||||
if (!fileDetails || !ICON_CONFIG.supportedFormats.includes(fileDetails.ext)) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
return await saveIconFile(iconData, fileDetails.ext);
|
||||
}
|
||||
catch (error) {
|
||||
if (showSpinner && !(error.response?.status === 404)) {
|
||||
throw error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Saves icon file to temporary location
|
||||
*/
|
||||
async function saveIconFile(iconData, extension) {
|
||||
const buffer = Buffer.from(iconData);
|
||||
if (IS_LINUX) {
|
||||
const iconPath = 'png/linux_temp.png';
|
||||
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
|
||||
return iconPath;
|
||||
}
|
||||
const { path: tempPath } = await dir();
|
||||
const iconPath = `${tempPath}/icon.${extension}`;
|
||||
await fsExtra.outputFile(iconPath, buffer);
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
// Extracts the domain from a given URL.
|
||||
@@ -1040,7 +1201,7 @@ async function handleOptions(options, url) {
|
||||
name,
|
||||
identifier: getIdentifier(url),
|
||||
};
|
||||
appOptions.icon = await handleIcon(appOptions);
|
||||
appOptions.icon = await handleIcon(appOptions, url);
|
||||
return appOptions;
|
||||
}
|
||||
|
||||
@@ -1157,7 +1318,6 @@ program
|
||||
log.setLevel('debug');
|
||||
}
|
||||
const appOptions = await handleOptions(options, url);
|
||||
log.debug('PakeAppOptions', appOptions);
|
||||
const builder = BuilderProvider.create(appOptions);
|
||||
await builder.prepare();
|
||||
await builder.build(url);
|
||||
|
||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pake-cli",
|
||||
"version": "3.2.0-beta11",
|
||||
"version": "3.2.0-beta15",
|
||||
"description": "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
@@ -49,19 +49,20 @@
|
||||
"exports": "./dist/cli.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.7.0",
|
||||
"@tauri-apps/cli": "^2.7.1",
|
||||
"@tauri-apps/api": "^2.8.0",
|
||||
"@tauri-apps/cli": "^2.8.1",
|
||||
"axios": "^1.11.0",
|
||||
"chalk": "^5.5.0",
|
||||
"chalk": "^5.6.0",
|
||||
"commander": "^11.1.0",
|
||||
"execa": "^9.6.0",
|
||||
"file-type": "^18.7.0",
|
||||
"fs-extra": "^11.3.1",
|
||||
"icon-gen": "^5.0.0",
|
||||
"loglevel": "^1.9.2",
|
||||
"ora": "^8.2.0",
|
||||
"pake-cli": "file:.yalc/pake-cli",
|
||||
"prompts": "^2.4.2",
|
||||
"psl": "^1.15.0",
|
||||
"sharp": "^0.33.5",
|
||||
"tmp-promise": "^3.0.3",
|
||||
"update-notifier": "^7.3.1"
|
||||
},
|
||||
@@ -72,16 +73,15 @@
|
||||
"@rollup/plugin-replace": "^6.0.2",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/node": "^20.19.10",
|
||||
"@types/node": "^20.19.11",
|
||||
"@types/page-icon": "^0.3.6",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/psl": "^1.11.0",
|
||||
"@types/tmp": "^0.2.6",
|
||||
"@types/update-notifier": "^6.0.8",
|
||||
"app-root-path": "^3.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"prettier": "^3.4.2",
|
||||
"rollup": "^4.46.2",
|
||||
"prettier": "^3.6.2",
|
||||
"rollup": "^4.46.3",
|
||||
"rollup-plugin-typescript2": "^0.36.0",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.9.2"
|
||||
|
||||
1971
pnpm-lock.yaml
generated
1971
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
12
rollup.config.js
vendored
12
rollup.config.js
vendored
@@ -23,6 +23,18 @@ export default {
|
||||
include: "bin/**",
|
||||
exclude: "node_modules/**",
|
||||
},
|
||||
external: (id) => {
|
||||
if (id === "bin/cli.ts" || id === "bin/dev.ts") return false;
|
||||
if (id.startsWith(".") || path.isAbsolute(id) || id.startsWith("@/"))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code === "UNRESOLVED_IMPORT") {
|
||||
return;
|
||||
}
|
||||
warn(warning);
|
||||
},
|
||||
plugins: [
|
||||
json(),
|
||||
typescript({
|
||||
|
||||
84
src-tauri/Cargo.lock
generated
84
src-tauri/Cargo.lock
generated
@@ -800,9 +800,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dlopen2"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6"
|
||||
checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
|
||||
dependencies = [
|
||||
"dlopen2_derive",
|
||||
"libc",
|
||||
@@ -2463,6 +2463,16 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-javascript-core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a"
|
||||
dependencies = [
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-metal"
|
||||
version = "0.2.2"
|
||||
@@ -2499,6 +2509,17 @@ dependencies = [
|
||||
"objc2-foundation 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-security"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"objc2 0.6.1",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-ui-kit"
|
||||
version = "0.3.1"
|
||||
@@ -2523,6 +2544,8 @@ dependencies = [
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-javascript-core",
|
||||
"objc2-security",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3627,9 +3650,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
|
||||
checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3638,13 +3661,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript-impl"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
|
||||
checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3951,11 +3974,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.34.0"
|
||||
version = "0.34.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
|
||||
checksum = "4daa814018fecdfb977b59a094df4bd43b42e8e21f88fddfc05807e6f46efaaf"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"block2 0.6.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics",
|
||||
"crossbeam-channel",
|
||||
@@ -4007,12 +4031,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.7.0"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "352a4bc7bf6c25f5624227e3641adf475a6535707451b09bb83271df8b7a6ac7"
|
||||
checksum = "a54629607ea3084a8b455c1ebe888cbdfc4de02fa5edb2e40db0dc97091007e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"embed_plist",
|
||||
@@ -4031,6 +4056,7 @@ dependencies = [
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.1",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
@@ -4058,9 +4084,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "182d688496c06bf08ea896459bf483eb29cdff35c1c4c115fb14053514303064"
|
||||
checksum = "67945dbaf8920dbe3a1e56721a419a0c3d085254ab24cff5b9ad55e2b0016e0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@@ -4074,15 +4100,15 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tauri-utils",
|
||||
"tauri-winres",
|
||||
"toml 0.8.23",
|
||||
"toml 0.9.5",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.3.1"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b54a99a6cd8e01abcfa61508177e6096a4fe2681efecee9214e962f2f073ae4a"
|
||||
checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
@@ -4107,9 +4133,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7945b14dc45e23532f2ded6e120170bbdd4af5ceaa45784a6b33d250fbce3f9e"
|
||||
checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -4284,9 +4310,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.7.1"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b1cc885be806ea15ff7b0eb47098a7b16323d9228876afda329e34e2d6c4676"
|
||||
checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
@@ -4295,20 +4321,23 @@ dependencies = [
|
||||
"jni",
|
||||
"objc2 0.6.1",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.14",
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.7.2"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe653a2fbbef19fe898efc774bc52c8742576342a33d3d028c189b57eb1d2439"
|
||||
checksum = "5bb0f10f831f75832ac74d14d98f701868f9a8adccef2c249b466cf70b607db9"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
@@ -4333,9 +4362,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330c15cabfe1d9f213478c9e8ec2b0c76dab26bb6f314b8ad1c8a568c1d186e"
|
||||
checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"brotli",
|
||||
@@ -4362,7 +4391,7 @@ dependencies = [
|
||||
"serde_with",
|
||||
"swift-rs",
|
||||
"thiserror 2.0.14",
|
||||
"toml 0.8.23",
|
||||
"toml 0.9.5",
|
||||
"url",
|
||||
"urlpattern",
|
||||
"uuid",
|
||||
@@ -5667,14 +5696,15 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.52.1"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9"
|
||||
checksum = "5698e50a589268aec06d2219f48b143222f7b5ad9aa690118b8dce0a8dcac574"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.1",
|
||||
"cookie",
|
||||
"crossbeam-channel",
|
||||
"dirs",
|
||||
"dpi",
|
||||
"dunce",
|
||||
"gdkx11",
|
||||
|
||||
@@ -15,13 +15,13 @@ crate-type = ["staticlib", "cdylib", "lib"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.3.1", features = [] }
|
||||
tauri-build = { version = "2.4.0", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.142"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
tokio = { version = "1.47.1", features = ["full"] }
|
||||
tauri = { version = "2.7.0", features = ["tray-icon", "image-ico", "image-png", "macos-proxy"] }
|
||||
tauri = { version = "2.8.0", features = ["tray-icon", "image-ico", "image-png", "macos-proxy"] }
|
||||
tauri-plugin-window-state = "2.4.0"
|
||||
tauri-plugin-oauth = "2.0.0"
|
||||
tauri-plugin-http = "2.5.1"
|
||||
|
||||
Reference in New Issue
Block a user