| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import { join } from 'node:path'
- import { fileURLToPath } from 'node:url'
- import { execFile } from 'node:child_process'
- import { promisify } from 'node:util'
- import {
- resolveDesktopAppId,
- resolveMacOSNotarizationEnvironment,
- resolveMacOSSigningEnvironment,
- } from './scripts/desktop-release-environment.mjs'
- import { notarizeMacOSDiskImageArtifact } from './scripts/notarize-macos-disk-images.mjs'
- import { verifyMacOSSignatureAfterSign } from './scripts/verify-macos-signature.mjs'
- import {
- createWindowsTokenSigner,
- installWindowsNsisBootstrapSigner,
- scrubWindowsSigningEnvironment,
- } from './scripts/windows-sign.mjs'
- import { resolveDesktopAutoUpdateConfig } from './scripts/desktop-auto-update-environment.mjs'
- import { desktopTargetBuildPaths, resolveDesktopBuildTarget } from './scripts/desktop-build-paths.mjs'
- import { installWindowsDirectoryInstaller } from './scripts/windows-directory-installer.mjs'
- /**
- * Create electron-builder configuration from one release environment.
- * @param {NodeJS.ProcessEnv} env - Packaging environment.
- * @param {NodeJS.Platform} hostPlatform - Build-host platform used when no explicit target is present.
- * @param {string} hostArch - Build-host architecture used when no explicit target is present.
- * @returns {object} electron-builder configuration.
- */
- export function createElectronBuilderConfig(
- env = process.env,
- hostPlatform = process.platform,
- hostArch = process.arch,
- ) {
- const appId = resolveDesktopAppId(env)
- const targetPlatform = env.DSH_DESKTOP_TARGET_PLATFORM
- const resolvedPlatform = targetPlatform ?? hostPlatform
- const resolvedArch = env.DSH_DESKTOP_TARGET_ARCH ?? hostArch
- if (env.DSH_DESKTOP_UNSIGNED !== undefined && !['0', '1'].includes(env.DSH_DESKTOP_UNSIGNED)) {
- throw new Error('desktop package: DSH_DESKTOP_UNSIGNED must be 0 or 1')
- }
- const unsigned = env.DSH_DESKTOP_UNSIGNED === '1'
- if (unsigned && resolvedPlatform !== 'win32') throw new Error('desktop package: unsigned builds require Windows')
- const packagesMacOS = targetPlatform === 'darwin' || (targetPlatform === undefined && hostPlatform === 'darwin')
- const packagesWindows = targetPlatform === 'win32'
- if (resolvedPlatform === 'win32') installWindowsDirectoryInstaller()
- const macOSSigning = packagesMacOS ? resolveMacOSSigningEnvironment(env) : undefined
- if (packagesMacOS) resolveMacOSNotarizationEnvironment(env)
- const windowsSigner = packagesWindows && !unsigned
- ? createWindowsTokenSigner({
- certificateFile: env.DSH_DESKTOP_WINDOWS_CER_FILE,
- signTool: env.DSH_DESKTOP_WINDOWS_SIGNTOOL,
- tokenPin: env.DSH_DESKTOP_WINDOWS_TOKEN_PIN,
- keyContainer: env.DSH_DESKTOP_WINDOWS_KEY_CONTAINER,
- })
- : undefined
- if (windowsSigner !== undefined) {
- installWindowsNsisBootstrapSigner({ sign: windowsSigner })
- }
- const update = unsigned ? undefined : resolveDesktopAutoUpdateConfig(env, resolvedPlatform, resolvedArch)
- const buildPaths = desktopTargetBuildPaths(resolveDesktopBuildTarget(env, hostPlatform, hostArch))
- return {
- appId,
- productName: 'DeepSeek Harness',
- artifactName: 'deepseek-harness-${version}-${os}-${arch}.${ext}',
- directories: { output: unsigned ? join(buildPaths.root, 'unsigned-artifacts') : buildPaths.artifacts },
- asar: true,
- electronDist: buildPaths.electron,
- electronFuses: { runAsNode: true },
- beforeBuild: async () => {
- if (resolvedPlatform !== 'win32') return true
- await promisify(execFile)('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File',
- fileURLToPath(new URL('./scripts/prepare-windows-installer.ps1', import.meta.url)),
- '-OutputDirectory', join(buildPaths.root, 'installer-ui')], {
- env: scrubWindowsSigningEnvironment(env), windowsHide: true,
- })
- if (windowsSigner !== undefined) {
- await windowsSigner({ path: join(buildPaths.root, 'installer-ui', 'window-frame.dll'), hash: 'sha256', isNest: false })
- }
- // A falsy result tells electron-builder to omit its production node_modules collection.
- return true
- },
- files: [
- 'lib/*.js',
- 'lib/*.cjs',
- 'renderer/**/*',
- 'package.json',
- { from: buildPaths.dsh, to: 'dsh', filter: ['**/*'] },
- // electron-builder excludes a source directory's root node_modules.
- { from: join(buildPaths.dsh, 'node_modules'), to: 'dsh/node_modules', filter: ['**/*'] },
- ],
- asarUnpack: [
- '**/*.{node,dylib,dll,so,exe}',
- '**/*.so.*',
- '**/spawn-helper',
- '**/@vscode/ripgrep/bin/rg',
- ],
- extraResources: [
- { from: buildPaths.runtime, to: 'runtime' },
- ],
- mac: {
- icon: fileURLToPath(new URL('./resources/icon-macos.png', import.meta.url)),
- category: 'public.app-category.developer-tools',
- identity: macOSSigning?.signingIdentity,
- forceCodeSigning: true,
- hardenedRuntime: true,
- // ASAR-unpacked native runtime files are pre-signed; PAK resources are sealed by their enclosing bundle.
- signIgnore: ['/Contents/Resources/app\\.asar\\.unpacked/dsh(?:/|$)', '/Contents/Resources/runtime/primary-runtime(?:/|$)', '\\.pak$'],
- notarize: true,
- target: ['dmg', 'zip'],
- },
- dmg: {
- sign: true,
- writeUpdateInfo: false,
- },
- afterSign: async context => {
- if (context.electronPlatformName !== 'darwin') return
- verifyMacOSSignatureAfterSign(context, macOSSigning ?? resolveMacOSSigningEnvironment(env))
- },
- artifactBuildCompleted: artifact => {
- if (!artifact.file.endsWith('.dmg')) return
- return notarizeMacOSDiskImageArtifact(
- artifact,
- env,
- macOSSigning ?? resolveMacOSSigningEnvironment(env),
- )
- },
- win: {
- icon: fileURLToPath(new URL('./resources/icon-windows.png', import.meta.url)),
- forceCodeSigning: !unsigned,
- signtoolOptions: {
- sign: windowsSigner,
- signingHashAlgorithms: ['sha256'],
- },
- target: ['nsis'],
- },
- linux: {
- category: 'Development',
- target: ['AppImage'],
- },
- nsis: {
- installerSidebar: join(buildPaths.root, 'installer-ui', 'uninstaller-sidebar.bmp'),
- uninstallerSidebar: join(buildPaths.root, 'installer-ui', 'uninstaller-sidebar.bmp'),
- include: fileURLToPath(new URL('./scripts/installer.nsh', import.meta.url)),
- oneClick: false,
- perMachine: false,
- allowElevation: false,
- allowToChangeInstallationDirectory: false,
- installerLanguages: ['en_US', 'zh_CN'],
- differentialPackage: true,
- },
- publish: update === undefined ? null : [{ provider: 'generic', url: update.publicUrl }],
- }
- }
- export default createElectronBuilderConfig()
|