diff --git a/packages/browser/src/gen/index.d.ts b/packages/browser/src/gen/index.d.ts index c0b387dac..56585c661 100644 --- a/packages/browser/src/gen/index.d.ts +++ b/packages/browser/src/gen/index.d.ts @@ -8997,7 +8997,7 @@ export namespace Browser { // Optional author?: { email: string; - } | undefined; + } | string | undefined; background_page?: string | undefined; chrome_settings_overrides?: { homepage?: string | undefined; diff --git a/packages/wxt/src/core/utils/__tests__/manifest.test.ts b/packages/wxt/src/core/utils/__tests__/manifest.test.ts index c406a1d1e..39d8cc5e2 100644 --- a/packages/wxt/src/core/utils/__tests__/manifest.test.ts +++ b/packages/wxt/src/core/utils/__tests__/manifest.test.ts @@ -1625,6 +1625,91 @@ describe('Manifest Utils', () => { ); }); }); + + describe('author field handling', () => { + it('should convert author object with email to string', async () => { + setFakeWxt({ + config: { + outDir, + manifestVersion: 3, + manifest: { + author: { email: 'example@example.com' }, + }, + }, + }); + const buildOutput = fakeBuildOutput(); + + const { manifest: actual } = await generateManifest([], buildOutput); + + expect(actual.author).toBe('example@example.com'); + }); + + it('should handle author object without email property', async () => { + setFakeWxt({ + config: { + outDir, + manifestVersion: 3, + manifest: { + author: {} as any, + }, + }, + }); + const buildOutput = fakeBuildOutput(); + + const { manifest: actual } = await generateManifest([], buildOutput); + + expect(actual.author).toBe(''); + }); + + it('should preserve author when already a string', async () => { + setFakeWxt({ + config: { + outDir, + manifestVersion: 3, + manifest: { + author: 'John Doe', + }, + }, + }); + const buildOutput = fakeBuildOutput(); + + const { manifest: actual } = await generateManifest([], buildOutput); + + expect(actual.author).toBe('John Doe'); + }); + + it('should handle undefined author', async () => { + setFakeWxt({ + config: { + outDir, + manifestVersion: 3, + manifest: {}, + }, + }); + const buildOutput = fakeBuildOutput(); + + const { manifest: actual } = await generateManifest([], buildOutput); + + expect(actual.author).toBeUndefined(); + }); + + it('should handle null author', async () => { + setFakeWxt({ + config: { + outDir, + manifestVersion: 3, + manifest: { + author: null as any, + }, + }, + }); + const buildOutput = fakeBuildOutput(); + + const { manifest: actual } = await generateManifest([], buildOutput); + + expect(actual.author).toBeUndefined(); + }); + }); }); describe('stripPathFromMatchPattern', () => { diff --git a/packages/wxt/src/core/utils/manifest.ts b/packages/wxt/src/core/utils/manifest.ts index 2f0b4c903..b01114e1c 100644 --- a/packages/wxt/src/core/utils/manifest.ts +++ b/packages/wxt/src/core/utils/manifest.ts @@ -76,7 +76,15 @@ export async function generateManifest( short_name: pkg?.shortName, icons: discoverIcons(buildOutput), }; - const userManifest = wxt.config.manifest; + const userManifest = { ...wxt.config.manifest }; + + if (typeof userManifest.author === 'object' && userManifest.author !== null) { + wxt.logger.warn( + 'manifest.author should be a string, not an object. Chromium browsers ignore this field, and Gecko-based (firefox based) only uses it for display.\nUpdate your config to: author: "Your Name"', + ); + userManifest.author = userManifest.author.email ?? ''; + } + if (userManifest.manifest_version) { delete userManifest.manifest_version; wxt.logger.warn(