Files
zeekay ea79c31098 fix(firefox): correct manifest extension ID format
- Change gecko ID from '{[email protected]}' to '[email protected]'
  (email-style IDs must not have curly braces)
- Use _execute_browser_action command key for Firefox MV2 instead of
  _execute_action (which is Chrome MV3 only)

Fixes Firefox extension validation errors that caused "corrupted" message.
2026-01-29 18:46:44 -08:00

207 lines
5.7 KiB
TypeScript

import path from 'path'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import svgr from 'vite-plugin-svgr'
import { defineConfig } from 'wxt'
const icons = {
16: 'assets/icons/icon16.png',
32: 'assets/icons/icon32.png',
48: 'assets/icons/icon48.png',
128: 'assets/icons/icon128.png',
}
const BASE_NAME = 'Lux Wallet'
const BASE_DESCRIPTION = 'Lux Wallet - A self-custody crypto wallet for the Lux ecosystem with multi-chain support.'
const BASE_VERSION = '1.0.0'
const BUILD_NUM = parseInt(process.env.BUILD_NUM || '0')
const EXTENSION_VERSION = `${BASE_VERSION}.${BUILD_NUM}`
export default defineConfig({
srcDir: 'src',
entrypointsDir: 'entrypoints',
publicDir: 'src/public',
outDir: process.env.WXT_ABSOLUTE_OUTDIR || undefined,
outDirTemplate: process.env.WXT_ABSOLUTE_OUTDIR ? '' : undefined,
imports: false,
modules: ['@wxt-dev/module-react'],
manifest: (env) => {
const isDevelopment = env.mode === 'development'
const BUILD_ENV = isDevelopment ? undefined : process.env.BUILD_ENV
const isFirefox = env.browser === 'firefox'
const isSafari = env.browser === 'safari'
const isChromium = !isFirefox && !isSafari
const EXTENSION_NAME_POSTFIX = BUILD_ENV === 'dev' ? 'DEV' : BUILD_ENV === 'beta' ? 'BETA' : ''
const name = EXTENSION_NAME_POSTFIX ? `${BASE_NAME} ${EXTENSION_NAME_POSTFIX}` : BASE_NAME
let description = BASE_DESCRIPTION
if (BUILD_ENV === 'beta') {
description = 'THIS EXTENSION IS FOR BETA TESTING'
}
if (BUILD_ENV === 'dev') {
description = 'THIS EXTENSION IS FOR DEV TESTING'
}
// Base permissions (cross-browser compatible)
const permissions: string[] = ['alarms', 'notifications', 'storage', 'tabs']
// Add Chrome-only permissions (sidePanel not supported on Firefox/Safari)
if (isChromium) {
permissions.push('sidePanel')
}
// Firefox MV2 uses _execute_browser_action, Chrome MV3 uses _execute_action
const commandKey = isFirefox ? '_execute_browser_action' : '_execute_action'
const manifest: Record<string, unknown> = {
name,
description,
version: EXTENSION_VERSION,
icons,
permissions,
commands: {
[commandKey]: {
suggested_key: {
default: 'Ctrl+Shift+L',
mac: 'Command+Shift+L',
},
description: 'Toggle Lux Wallet',
},
},
}
// Chrome/Chromium-specific settings (Chrome, Brave, Arc, Edge, Opera, Comet, Atlas, etc.)
if (isChromium) {
manifest.minimum_chrome_version = '116'
manifest.action = {
default_icon: icons,
}
manifest.externally_connectable = {
ids: [],
matches: BUILD_ENV === 'prod'
? ['https://app.lux.exchange/*', 'https://*.lux.exchange/*', 'https://*.lux.network/*']
: ['https://app.lux.exchange/*', 'https://*.lux.exchange/*', 'https://*.lux.network/*', 'http://localhost/*', 'http://127.0.0.1/*'],
}
}
// Firefox-specific settings
if (isFirefox) {
manifest.browser_specific_settings = {
gecko: {
id: '[email protected]',
strict_min_version: '109.0',
},
}
manifest.browser_action = {
default_icon: icons,
default_title: BASE_NAME,
}
}
// Safari-specific settings (macOS and iOS)
if (isSafari) {
manifest.browser_specific_settings = {
safari: {
strict_min_version: '15.4',
},
}
// Safari uses action like Chrome but with some differences
manifest.action = {
default_icon: icons,
default_title: BASE_NAME,
}
}
return manifest
},
vite: (env) => {
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const isProduction = env.mode === 'production'
return {
define: {
__DEV__: !isProduction,
global: 'globalThis',
'process.env.NODE_ENV': JSON.stringify(env.mode || 'development'),
'process.env.VERSION': JSON.stringify(EXTENSION_VERSION),
'process.env.IS_LUX_EXTENSION': '"true"',
},
resolve: {
extensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.js'],
alias: {
'@': path.resolve(__dirname, 'src'),
'react-native': 'react-native-web',
},
},
plugins: [
svgr({
svgrOptions: {
icon: false,
ref: true,
titleProp: true,
exportType: 'named',
svgo: true,
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: { removeViewBox: false },
},
},
'removeDimensions',
],
},
},
include: '**/*.svg',
}),
nodePolyfills({
globals: {
process: true,
},
}),
].filter(Boolean),
optimizeDeps: {
include: [
'buffer',
'react-native-web',
'ethers',
'eventemitter3',
],
},
build: {
sourcemap: isProduction ? false : 'hidden',
minify: isProduction ? 'esbuild' : undefined,
rollupOptions: {
output: {
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
},
},
chunkSizeWarningLimit: 800,
},
}
},
dev: {
server: {
port: 9998,
},
},
webExt: {
startUrls: ['https://app.lux.exchange'],
chromiumArgs: ['--user-data-dir=./.wxt/chrome-data'],
keepProfileChanges: true,
firefoxProfile: './.wxt/firefox-data',
},
})