Skip to content

Commit 08636f5

Browse files
committed
fix(browser-extension): resolve bundled web-ext binary
1 parent 583459b commit 08636f5

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

storage/framework/core/browser-extension/src/firefox-addons.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ExtensionConfig, FirefoxAddonsConfig } from './types'
2-
import { existsSync, readdirSync } from 'node:fs'
2+
import { existsSync, readFileSync, readdirSync } from 'node:fs'
33
import { mkdir, mkdtemp, rm } from 'node:fs/promises'
4+
import { createRequire } from 'node:module'
45
import { tmpdir } from 'node:os'
56
import { join, resolve } from 'node:path'
67
import { buildExtension, resolveOutdir } from './build'
@@ -57,6 +58,27 @@ export function firefoxListingMetadata(config: ExtensionConfig, store: FirefoxAd
5758
}
5859
}
5960

61+
/** Resolve web-ext from PATH or from this package's declared dependency. */
62+
export function resolveWebExtExecutable(which: (command: string) => string | null = Bun.which): string | undefined {
63+
const fromPath = which('web-ext')
64+
if (fromPath)
65+
return fromPath
66+
67+
try {
68+
const require = createRequire(import.meta.url)
69+
const packagePath = require.resolve('web-ext/package.json')
70+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8')) as { bin?: string | Record<string, string> }
71+
const relativeBin = typeof packageJson.bin === 'string' ? packageJson.bin : packageJson.bin?.['web-ext']
72+
if (!relativeBin)
73+
return undefined
74+
const executable = resolve(packagePath, '..', relativeBin)
75+
return existsSync(executable) ? executable : undefined
76+
}
77+
catch {
78+
return undefined
79+
}
80+
}
81+
6082
/** Build and submit a Firefox extension through Mozilla's official web-ext/AMO v5 flow. */
6183
export async function publishFirefoxExtension(config: ExtensionConfig, options: FirefoxPublishOptions): Promise<FirefoxPublishResult> {
6284
if (!config.geckoId)
@@ -69,7 +91,7 @@ export async function publishFirefoxExtension(config: ExtensionConfig, options:
6991

7092
const sourceDir = resolve(cwd, resolveOutdir(config, 'firefox'))
7193
const artifactsDir = resolve(cwd, store.artifactsDir ?? 'web-ext-artifacts')
72-
const executable = Bun.which('web-ext')
94+
const executable = resolveWebExtExecutable()
7395
if (!executable)
7496
throw new Error('[browser-extension] web-ext is unavailable; reinstall @stacksjs/browser-extension dependencies')
7597
await mkdir(artifactsDir, { recursive: true })

storage/framework/core/browser-extension/tests/store-publishing.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os'
55
import { join } from 'node:path'
66
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
77
import { ChromeWebStoreClient, chromeWebStoreServiceAccountAssertion } from '../src/chrome-web-store'
8-
import { firefoxListingMetadata } from '../src/firefox-addons'
8+
import { firefoxListingMetadata, resolveWebExtExecutable } from '../src/firefox-addons'
99

1010
const chromeConfig: ChromeWebStoreConfig = {
1111
publisherId: 'publisher-123',
@@ -107,4 +107,9 @@ describe('Firefox Add-ons metadata', () => {
107107
expect(firefoxListingMetadata(config, {})).toBeUndefined()
108108
expect(() => firefoxListingMetadata(config, { license: 'MIT' })).toThrow('both firefoxAddons.license and firefoxAddons.categories')
109109
})
110+
111+
it('resolves the declared web-ext dependency when it is absent from PATH', () => {
112+
const executable = resolveWebExtExecutable(() => null)
113+
expect(executable).toEndWith('/web-ext/bin/web-ext.js')
114+
})
110115
})

0 commit comments

Comments
 (0)