diff --git a/apps/stage-tamagotchi/electron-builder.config.ts b/apps/stage-tamagotchi/electron-builder.config.ts index 7c5739f31..a55599a0e 100644 --- a/apps/stage-tamagotchi/electron-builder.config.ts +++ b/apps/stage-tamagotchi/electron-builder.config.ts @@ -12,6 +12,7 @@ function hasXcode26OrAbove() { try { const output = execSync('xcodebuild -version') .toString() + // eslint-disable-next-line e18e/prefer-static-regex .match(/Xcode (\d+)/) if (!output) return false @@ -150,5 +151,68 @@ export default { provider: 'github', owner: 'moeru-ai', repo: 'airi', + // NOTICE: `channel: 'latest-${arch}'` matters because electron-builder expands + // `${arch}` before it writes any publish metadata, and electron-updater later + // reuses that expanded channel string when deciding which `*.yml` file to fetch. + // + // Without this, the updater would look for `latest-mac.yml` for both x64 and arm64 macOS builds, + // which means the x64 build would be used for arm64 (Apple Silicon) users, causing suboptimal performance and higher resource usage. By embedding `${arch}` + // into the channel name, we ensure that the updater looks for `latest-x64-mac.yml` and `latest-arm64-mac.yml` respectively. + // + // This is how channel name was constructed: + // + // 1. `expandPublishConfig(...)` expands string values in the publish config. + // That is where `latest-${arch}` becomes `latest-x64` or `latest-arm64`. + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/app-builder-lib/src/publish/PublishManager.ts#L521-L532 + // + // 2. The expanded publish config is written into `app-update.yml`. + // The packaged app therefore carries `channel: latest-x64` or + // `channel: latest-arm64`, not the literal template string. + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/app-builder-lib/src/publish/PublishManager.ts#L93-L96 + // + // 3. electron-builder also uses that expanded channel when generating update + // metadata files. `getUpdateInfoFileName(channel, packager, arch)` builds the + // filename as: + // `${channel}${osSuffix}${getArchPrefixForUpdateFile(arch, packager)}.yml` + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/app-builder-lib/src/publish/updateInfoBuilder.ts#L65-L68 + // + // 4. For macOS, `osSuffix` is `-mac` and `getArchPrefixForUpdateFile(...)` + // returns an empty string. So: + // `latest-x64` -> `latest-x64-mac.yml` + // `latest-arm64` -> `latest-arm64-mac.yml` + // This is the publish-time side of the behavior. + // + // 5. At runtime, electron-updater reads the embedded `app-update.yml` and takes + // its `channel` value. It does not reconstruct `latest-${arch}` itself; it + // consumes the already-expanded value from step 2. + // + // 6. `Provider.getChannelFilePrefix()` appends the platform suffix: + // - macOS -> `-mac` + // - Windows -> `` + // - Linux x64 -> `-linux` + // - Linux non-x64 -> `-linux-${arch}` + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/electron-updater/src/providers/Provider.ts#L44-L52 + // + // 7. `getCustomChannelName(channel)` then returns: + // `${channel}${this.getChannelFilePrefix()}` + // So the updater turns: + // `latest-x64` -> `latest-x64-mac` + // `latest-arm64` -> `latest-arm64-mac` + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/electron-updater/src/providers/Provider.ts#L58-L60 + // + // 8. GitHubProvider passes that channel name into `getChannelFilename(channel)`, + // which simply appends `.yml`, so the final lookup becomes: + // `latest-x64-mac.yml` + // `latest-arm64-mac.yml` + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/electron-updater/src/util.ts#L27-L29 + // https://github.com/electron-userland/electron-builder/blob/ed422f36540a93e9bd2a19bc7a5e729bf2b033ea/packages/electron-updater/src/providers/GitHubProvider.ts#L132-L145 + // + // Resulting filenames with this config: + // - macOS x64 -> `latest-x64-mac.yml` + // - macOS arm64 -> `latest-arm64-mac.yml` + // - Windows x64 -> `latest-x64.yml` + // - Linux x64 -> `latest-x64-linux.yml` + // - Linux arm64 -> `latest-arm64-linux-arm64.yml` + channel: 'latest-${arch}', }, } satisfies Configuration diff --git a/apps/stage-tamagotchi/electron-builder.yml b/apps/stage-tamagotchi/electron-builder.yml deleted file mode 100644 index 041da06e3..000000000 --- a/apps/stage-tamagotchi/electron-builder.yml +++ /dev/null @@ -1,79 +0,0 @@ -appId: ai.moeru.airi -productName: AIRI - -directories: - output: dist - buildResources: build - -files: - - out/** - - resources/** - - package.json - - '!**/.vscode/*' - - '!src/**/*' - - '!**/node_modules/**/{CHANGELOG.md,README.md,README,readme.md,readme}' - - '!**/node_modules/**/{.turbo,test,src,__tests__,tests,example,examples}' - - 'node_modules/debug/src/**' - - '!electron.vite.config.{js,ts,mjs,cjs}' - - '!vite.config.{js,ts,mjs,cjs}' - - '!uno.config.{js,ts,mjs,cjs}' - - '!{.eslintcache,eslint.config.ts,.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' - - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' - - '!{tsconfig.json}' - -asar: true -asarUnpack: - - '**/*.node' # native binaries - -extraMetadata: - name: ai.moeru.airi - main: 'out/main/index.js' - homepage: 'https://airi.moeru.ai/docs/' - repository: 'https://github.com/moeru-ai/airi' - license: 'MIT' - -win: - executableName: airi -nsis: - artifactName: ${productName}-${version}-windows-${arch}-setup.${ext} - shortcutName: ${productName} - uninstallDisplayName: ${productName} - createDesktopShortcut: always - deleteAppDataOnUninstall: true - oneClick: false - allowToChangeInstallationDirectory: true - -mac: - entitlementsInherit: build/entitlements.mac.plist - extendInfo: - - NSMicrophoneUsageDescription: 'AIRI requires microphone access for voice interaction' - - NSCameraUsageDescription: 'AIRI requires camera access for vision understanding' - # If still fails, check: - # https://github.com/electron-userland/electron-builder/issues/3989#issuecomment-557013674 - notarize: false - hardenedRuntime: false - executableName: airi - icon: icon.icon -dmg: - artifactName: ${productName}-${version}-darwin-${arch}.${ext} - -linux: - target: - - deb - - rpm - category: Utility - synopsis: 'AI VTuber/Waifu chatbot app inspired by Neuro-sama.' - description: 'AIRI is an AI VTuber/Waifu chatbot supporting Live2D/VRM avatars, featuring human-like interactions and modular stage-based rendering.' - executableName: airi - artifactName: ${productName}-${version}-linux-${arch}.${ext} - icon: build/icons/icon.png - -appImage: - artifactName: ${productName}-${version}-linux-${arch}.${ext} - -npmRebuild: false - -publish: - provider: github - owner: moeru-ai - repo: airi