Files
Capsule/build/config.mjs

73 lines
3.3 KiB
JavaScript

/** Build identities and release requirements shared by packaging and tests. */
export const APP_ID = 'com.thetempusproject.capsule'
/** Validate a public feed without embedding credentials in installed copies. */
export function validateFeedUrl(value) {
let url
try {
url = new URL(value)
} catch {
throw new Error('CAPSULE_UPDATE_URL must be an absolute HTTPS directory URL.')
}
if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash ||
!url.pathname.endsWith('/') || /^(localhost|127\.|\[?::1\]?)/i.test(url.hostname) ||
/(^|\.)example\.(com|org|net)$|\.invalid$/i.test(url.hostname)) {
throw new Error('Use a permanent public HTTPS feed ending in /, without credentials, query, or fragment.')
}
return url.href
}
/** Return a Windows build config; public releases fail closed without signing. */
export function createBuildConfig({ release = false, testUpdates = false, bootstrap = false, env = process.env } = {}) {
if (release && testUpdates) throw new Error('Test updates cannot be combined with a public release.')
if (bootstrap && !testUpdates) throw new Error('Bootstrap requires test updates.')
const url = testUpdates ? validateFeedUrl(env.CAPSULE_TEST_UPDATE_URL) : release ? validateFeedUrl(env.CAPSULE_UPDATE_URL) : null
if (testUpdates && !new URL(url).pathname.endsWith('/capsule/testfeed/')) {
throw new Error('Test updates require a separate /capsule/testfeed/ URL.')
}
const publisher = env.CAPSULE_PUBLISHER_NAME?.trim()
if (release && !publisher) {
throw new Error('CAPSULE_PUBLISHER_NAME must match the signing certificate subject CN.')
}
if (release && !env.CSC_LINK && !env.CSC_NAME) {
throw new Error('Set CSC_LINK (certificate) or CSC_NAME (Windows certificate store identity).')
}
return {
appId: release ? APP_ID : `${APP_ID}.local`,
productName: release ? 'Capsule' : 'Capsule Local',
executableName: release ? 'Capsule' : 'Capsule Local',
directories: { output: release ? 'dist/release' : testUpdates ? bootstrap ? 'dist/test-bootstrap' : 'dist/test' : 'dist/local' },
files: ['out/**/*', 'package.json'],
asar: true,
npmRebuild: false,
forceCodeSigning: release,
extraMetadata: {
// Keep the release userData path compatible with the original dev app.
name: release ? 'capsule' : 'capsule-local',
...(bootstrap ? { version: '0.1.0' } : {}),
capsuleUpdates: { enabled: release || testUpdates, testing: testUpdates }
},
artifactName: release || testUpdates ? 'Capsule-${version}-${arch}-Setup.${ext}' : 'Capsule-Local-${version}-${arch}-Setup.${ext}',
win: {
icon: 'build/icon.ico',
target: [{ target: 'nsis', arch: ['x64'] }],
verifyUpdateCodeSignature: !testUpdates,
signExecutable: release,
...(release ? { signtoolOptions: {
publisherName: publisher,
signingHashAlgorithms: ['sha256'],
...(env.CSC_NAME ? { certificateSubjectName: env.CSC_NAME } : {})
} } : {})
},
nsis: {
oneClick: true,
perMachine: false,
allowElevation: false,
deleteAppDataOnUninstall: false,
runAfterFinish: false,
shortcutName: release ? 'Capsule' : 'Capsule Local'
},
publish: release || testUpdates ? [{ provider: 'generic', url, channel: 'latest', useMultipleRangeRequest: false }] : null
}
}