Repository navigation
Expand file tree
/
Copy pathesbuild.config.js
More file actions
163 lines (149 loc) · 6.35 KB
/
Copy pathesbuild.config.js
File metadata and controls
163 lines (149 loc) · 6.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import esbuild from 'esbuild'
import { cpSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { execSync } from 'node:child_process'
const __dirname = dirname(fileURLToPath(import.meta.url))
const isWatch = process.argv.includes('--watch')
const target = process.argv.find(arg => arg.startsWith('--target='))?.split('=')[1] || 'chromium'
const supportedTargets = new Set(['chromium', 'firefox', 'safari'])
if (!supportedTargets.has(target)) {
throw new Error(`Unsupported build target: ${target}`)
}
const srcDir = resolve(__dirname, 'src')
const distDir = resolve(__dirname, target === 'chromium' ? 'dist' : `dist-${target}`)
// Ensure dist directories exist
if (!isWatch) rmSync(distDir, { recursive: true, force: true })
mkdirSync(resolve(distDir, 'icons'), { recursive: true })
function manifestForTarget() {
const manifest = JSON.parse(readFileSync(resolve(srcDir, 'manifest.json'), 'utf8'))
// The Chromium manifest avoids broad host matches (a CWS in-depth review
// trigger): content scripts run on a curated list of Nostr clients plus
// localhost, and any other site is enabled at runtime via activeTab +
// optional host grant + dynamic registration. AMO and Safari have no such
// review trigger, so those targets keep the simpler broad injection and
// need neither scripting nor activeTab.
const BROAD_MATCHES = ['https://*/*', 'http://localhost/*', 'http://127.0.0.1/*']
if (target === 'firefox') {
// Firefox MV3 uses event-page background scripts while Chromium uses
// service workers. The bundled background is an IIFE, so no module flag is
// required here.
manifest.background = {
scripts: ['background.js'],
}
manifest.permissions = ['storage']
// Firefox keeps optional host permissions for the legacy HTTP pairing
// flow; the Chromium manifest omits them because CWS counts optional
// broad host permissions towards the in-depth-review trigger.
manifest.optional_host_permissions = ['http://*/*', 'https://*/*']
for (const cs of manifest.content_scripts) cs.matches = BROAD_MATCHES
// Chromium never gates WebSockets on host permissions, so the base
// manifest omits these. Firefox's behaviour is less clearly documented;
// keep the declared (user-optional in MV3) relay permissions there.
// Match patterns ignore ports, so the loopback entries cover any port.
manifest.host_permissions = ['wss://*/*', 'ws://localhost/*', 'ws://127.0.0.1/*']
manifest.browser_specific_settings = {
gecko: {
id: 'bark@forgesworn.local',
// 140 (ESR) rather than the technical floor of 128 (MAIN-world
// content scripts): data_collection_permissions below is only
// understood from 140, and the declaration should be shown to
// every user who can install.
strict_min_version: '140.0',
// Required for new AMO submissions. Bark collects nothing.
data_collection_permissions: {
required: ['none'],
},
},
// Opt in to Firefox for Android. Without this key AMO lists Bark as
// desktop-only and Android users cannot install it. This is the only
// supported extension route on GrapheneOS — Vanadium runs no
// extensions at all. Android has no windows API, so the approval
// surface falls back to a tab (see approvalSurfaceKind in
// background.js). 142 rather than the desktop floor of 140:
// data_collection_permissions above only reached Android in 142, and
// web-ext lint flags the mismatch.
gecko_android: {
strict_min_version: '142.0',
},
}
}
if (target === 'safari') {
manifest.name = 'Bark for Safari'
manifest.background = {
service_worker: 'background.js',
}
manifest.permissions = ['storage']
manifest.optional_host_permissions = ['http://*/*', 'https://*/*']
// Safari lacks reliable MAIN-world content script support, so it keeps
// the script-tag injection path (see __BARK_INJECT_PROVIDER__ below).
manifest.content_scripts = manifest.content_scripts.filter(cs => cs.world !== 'MAIN')
for (const cs of manifest.content_scripts) cs.matches = BROAD_MATCHES
manifest.web_accessible_resources = [
{
resources: ['provider.js'],
matches: ['https://*/*', 'http://localhost/*', 'http://127.0.0.1/*'],
},
]
}
return manifest
}
// Copy static files to dist
function copyStatic() {
writeFileSync(
resolve(distDir, 'manifest.json'),
`${JSON.stringify(manifestForTarget(), null, 2)}\n`,
)
cpSync(resolve(srcDir, 'popup.html'), resolve(distDir, 'popup.html'))
cpSync(resolve(srcDir, 'icons'), resolve(distDir, 'icons'), { recursive: true })
cpSync(resolve(srcDir, 'approve.html'), resolve(distDir, 'approve.html'))
cpSync(resolve(srcDir, 'diagnostic.html'), resolve(distDir, 'diagnostic.html'))
cpSync(resolve(srcDir, '_locales'), resolve(distDir, '_locales'), { recursive: true })
}
copyStatic()
// Bundle background.js and popup.js as IIFE for Chrome extension context
const buildOptions = {
entryPoints: [
resolve(srcDir, 'background.js'),
resolve(srcDir, 'popup.js'),
resolve(srcDir, 'approve.js'),
resolve(srcDir, 'content-script.js'),
resolve(srcDir, 'provider.js'),
],
bundle: true,
format: 'iife',
outdir: distDir,
logLevel: 'info',
define: {
// Safari falls back to script-tag provider injection; Chromium and
// Firefox use the declarative MAIN-world content script instead.
__BARK_INJECT_PROVIDER__: target === 'safari' ? 'true' : 'false',
},
plugins: [
{
name: 'copy-static-on-rebuild',
setup(build) {
build.onEnd(() => {
copyStatic()
})
},
},
],
}
const isPackage = process.argv.includes('--package')
if (isWatch) {
const ctx = await esbuild.context(buildOptions)
await ctx.watch()
console.log(`Watching ${target} build for changes...`)
} else {
await esbuild.build(buildOptions)
if (isPackage) {
const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf8'))
const zipName = target === 'chromium'
? `bark-v${pkg.version}.zip`
: `bark-${target}-v${pkg.version}.zip`
rmSync(resolve(__dirname, zipName), { force: true })
execSync(`cd "${distDir}" && zip -r "../${zipName}" .`)
console.log(`Packaged: ${zipName}`)
}
}