Ctrl K
ComunidadGuías…

forge.config.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { execFileSync } from 'node:child_process';
import type { ForgeConfig } from '@electron-forge/shared-types';
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
import { MakerZIP } from '@electron-forge/maker-zip';
import { MakerDeb } from '@electron-forge/maker-deb';
import { MakerRpm } from '@electron-forge/maker-rpm';
import { VitePlugin } from '@electron-forge/plugin-vite';
import { FusesPlugin } from '@electron-forge/plugin-fuses';
import { FuseV1Options, FuseVersion } from '@electron/fuses';

// Real Developer ID signing + notarization run only when the Apple credentials
// are present in the environment (set from GitHub secrets in CI — see
// .github/workflows/release.yml and README → macOS code signing). Without them
// (local dev, PRs, forks) the macOS build falls back to the ad-hoc re-sign in the
// postPackage hook below, which runs but shows an "unidentified developer" prompt.
const APPLE_SIGNING_IDENTITY = process.env.APPLE_SIGNING_IDENTITY;
const notarizeMac = Boolean(APPLE_SIGNING_IDENTITY);

const config: ForgeConfig = {
  packagerConfig: {
    asar: true,
    // Extensionless base path; packager appends .icns (macOS) / .ico (Windows).
    icon: 'assets/icon',
    // Lowercase the binary ONLY on Linux, where the deb/rpm makers require it
    // (else "could not find the Electron app binary at .../dombot"). macOS and
    // Windows keep "DomBot" so the user-facing name (Finder, menu bar, Gatekeeper,
    // taskbar) is correctly cased — and so nothing has to rewrite Info.plist after
    // signing, which would break the Developer ID signature.
    executableName: process.platform === 'linux' ? 'dombot' : undefined,
    // Developer ID signing (macOS). Hardened runtime is required for notarization;
    // @electron/osx-sign applies Electron-appropriate default entitlements.
    osxSign: notarizeMac
      ? {
          identity: APPLE_SIGNING_IDENTITY,
          optionsForFile: () => ({ hardenedRuntime: true }),
        }
      : undefined,
    // Notarization via App Store Connect API key (set from secrets).
    osxNotarize: notarizeMac
      ? {
          appleApiKey: process.env.APPLE_API_KEY_PATH as string,
          appleApiKeyId: process.env.APPLE_API_KEY_ID as string,
          appleApiIssuer: process.env.APPLE_API_ISSUER as string,
        }
      : undefined,
  },
  rebuildConfig: {},
  hooks: {
    // macOS, after Packager finishes and before the makers zip/dmg the bundle:
    //  - Signed path (osxSign/osxNotarize ran during packaging): staple the
    //    notarization ticket to the app so it validates offline.
    //  - Ad-hoc path (local/dev/PR): deep ad-hoc re-sign. Flipping fuses and
    //    Packager's Info.plist edits invalidate the stock Electron signature, so
    //    macOS would reject the app as "damaged"; re-signing restores a valid
    //    signature (users then get the ordinary "unidentified developer" prompt).
    postPackage: async (_forgeConfig, { platform, outputPaths }) => {
      if (platform !== 'darwin') return;
      for (const outputPath of outputPaths) {
        const app = `${outputPath}/DomBot.app`;
        if (notarizeMac) {
          execFileSync('xcrun', ['stapler', 'staple', app], {
            stdio: 'inherit',
          });
        } else {
          execFileSync('codesign', ['--force', '--deep', '--sign', '-', app], {
            stdio: 'inherit',
          });
        }
      }
    },
  },
  makers: [
    new MakerSquirrel({
      setupIcon: 'assets/icon.ico',
    }),
    // macOS ships a .zip here; the downloadable .dmg is assembled from the
    // packaged .app in CI with hdiutil (see .github/workflows/release.yml) to
    // avoid maker-dmg's fragile native `appdmg` dependency.
    new MakerZIP({}, ['darwin']),
    new MakerRpm({
      options: {
        icon: 'assets/icon.png',
      },
    }),
    new MakerDeb({
      options: {
        icon: 'assets/icon.png',
      },
    }),
  ],
  plugins: [
    new VitePlugin({
      // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
      // If you are familiar with Vite configuration, it will look really familiar.
      build: [
        {
          // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
          entry: 'src/electron/index.ts',
          config: 'vite.main.config.ts',
          target: 'main',
        },
        {
          entry: 'src/preload.ts',
          config: 'vite.preload.config.ts',
          target: 'preload',
        },
      ],
      renderer: [
        {
          name: 'main_window',
          config: 'vite.renderer.config.mts',
        },
      ],
    }),
    // Fuses are used to enable/disable various Electron functionality
    // at package time, before code signing the application
    new FusesPlugin({
      version: FuseVersion.V1,
      [FuseV1Options.RunAsNode]: false,
      [FuseV1Options.EnableCookieEncryption]: true,
      [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
      [FuseV1Options.EnableNodeCliInspectArguments]: false,
      [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
      [FuseV1Options.OnlyLoadAppFromAsar]: true,
    }),
  ],
};

export default config;