Skip to content

Commit 16a16aa

Browse files
committed
feat: add safari support (WIP)
1 parent 91257e1 commit 16a16aa

File tree

6 files changed

+211
-2
lines changed

6 files changed

+211
-2
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Release on the App Store for Safari Extensions
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
build:
8+
runs-on: macos-latest
9+
10+
steps:
11+
- uses: actions/checkout@v5
12+
13+
- uses: pnpm/action-setup@v4
14+
with:
15+
version: 10
16+
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: 22
20+
cache: 'pnpm'
21+
22+
- name: Install dependencies
23+
run: pnpm install
24+
25+
- name: Convert to Safari extension
26+
run: pnpm build:safari
27+
28+
- name: Import signing certificate
29+
run: |
30+
echo "$MACOS_CERTIFICATE" | base64 --decode > cert.p12
31+
security create-keychain -p "" build.keychain
32+
security import cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
33+
security list-keychains -s build.keychain
34+
security unlock-keychain -p "" build.keychain
35+
env:
36+
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
37+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
38+
39+
- name: Build the Xcode archive
40+
run: |
41+
xcodebuild archive \
42+
-project .output/CSStats+/

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"build:all": "pnpm build && pnpm build:firefox && pnpm build:edge",
1212
"build:edge": "wxt build -b edge",
1313
"build:firefox": "wxt build -b firefox",
14+
"build:safari": "wxt build -b safari",
1415
"zip": "wxt zip",
1516
"zip:all": "pnpm zip && pnpm zip:firefox && pnpm zip:edge",
1617
"zip:edge": "wxt zip -b edge",
@@ -32,6 +33,7 @@
3233
"@types/react-dom": "^19.2.2",
3334
"@wxt-dev/module-react": "^1.1.5",
3435
"typescript": "^5.9.3",
35-
"wxt": "^0.20.13"
36+
"wxt": "^0.20.13",
37+
"wxt-module-safari-xcode": "^0.1.0"
3638
}
3739
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
diff --git a/dist/index.d.ts b/dist/index.d.ts
2+
index 9b2c8c403b6a5dcf28ef118cddac08e65340ef70..a35824411fc454dd2864035100a19920c1eaf097 100644
3+
--- a/dist/index.d.ts
4+
+++ b/dist/index.d.ts
5+
@@ -20,6 +20,21 @@ interface SafariXcodeOptions {
6+
* If not provided, the generated Xcode project will need to have the development team set manually
7+
*/
8+
developmentTeam?: string;
9+
+ /**
10+
+ * Output path for the Xcode project
11+
+ * Defaults to '.output/{projectName}/' directory
12+
+ */
13+
+ outputPath?: string;
14+
+ /**
15+
+ * Project type
16+
+ * Defaults to "both" (MacOS and iOS)
17+
+ */
18+
+ projectType?: 'macos' | 'ios' | 'both';
19+
+ /**
20+
+ * Open the Xcode project after creation
21+
+ * Defaults to false
22+
+ */
23+
+ openProject?: boolean;
24+
}
25+
declare const _default: wxt.WxtModule<SafariXcodeOptions>;
26+
27+
diff --git a/dist/index.js b/dist/index.js
28+
index 22b72c5c99e6b72c77b7487e4b82127395f44c4b..0df90098a7cabd8370d36aa72498eeda46bad653 100644
29+
--- a/dist/index.js
30+
+++ b/dist/index.js
31+
@@ -1,5 +1,6 @@
32+
// src/index.ts
33+
import "wxt";
34+
+import fs2 from "fs/promises";
35+
import { defineWxtModule } from "wxt/modules";
36+
import { $ } from "zx";
37+
38+
@@ -10,7 +11,7 @@ import fs from "fs/promises";
39+
async function updateProjectConfig(options) {
40+
const projectConfigPath = path.resolve(
41+
options.rootPath,
42+
- `.output/${options.projectName}/${options.projectName}.xcodeproj/project.pbxproj`
43+
+ `${options.outputPath}/${options.projectName}.xcodeproj/project.pbxproj`
44+
);
45+
const packageJsonModule = await import(path.resolve(options.rootPath, "package.json"), {
46+
with: { type: "json" }
47+
@@ -49,7 +50,7 @@ async function updateProjectConfig(options) {
48+
await fs.writeFile(projectConfigPath, newContent);
49+
}
50+
async function updateInfoPlist(options) {
51+
- const projectPath = path.resolve(options.rootPath, ".output", options.projectName);
52+
+ const projectPath = path.resolve(options.rootPath, options.outputPath);
53+
const files = await globby("**/*.plist", {
54+
cwd: projectPath
55+
});
56+
@@ -78,28 +79,48 @@ var index_default = defineWxtModule({
57+
return;
58+
}
59+
const { appCategory, bundleIdentifier, developmentTeam } = options ?? {};
60+
- const projectName = options?.projectName ?? wxt.config.manifest.name;
61+
+ const projectName = options?.projectName ?? wxt.config.manifest.name ?? await fs2.readFile(`${wxt.config.root}/package.json`, "utf-8").then((data) => JSON.parse(data).name);
62+
if (!projectName || !appCategory || !bundleIdentifier) {
63+
wxt.logger.warn(
64+
"Safari Xcode module is not configured properly. Please provide projectName, appCategory and bundleIdentifier."
65+
);
66+
return;
67+
}
68+
+ const inputPath = `.output/safari-mv${wxt.config.manifestVersion}`;
69+
+ const outputPath = options?.outputPath ?? `.output/${projectName}/`;
70+
+ const projectType = options?.projectType ?? "both";
71+
+ const openProject = options?.openProject ?? false;
72+
wxt.hook("build:done", async (wxt2) => {
73+
- wxt2.logger.info("Converting Safari extension to Xcode project...");
74+
+ wxt2.logger.info(`Converting ${highlight("Safari extension")} to ${highlight("Xcode project")}...`);
75+
+ if (process.platform !== "darwin") {
76+
+ const error = new Error("Safari Xcode conversion requires macOS.");
77+
+ wxt2.logger.error("Safari Xcode conversion is only supported on macOS.", error);
78+
+ throw error;
79+
+ }
80+
try {
81+
- wxt2.logger.info("Running safari-web-extension-converter...");
82+
- await $`xcrun safari-web-extension-converter --bundle-identifier ${bundleIdentifier} --force --project-location .output .output/safari-mv3`;
83+
- wxt2.logger.info("Updating Xcode project config...");
84+
+ wxt2.logger.info(`Running ${highlight("safari-web-extension-converter")}...`);
85+
+ const options2 = [
86+
+ `--bundle-identifier "${bundleIdentifier}"`,
87+
+ `--project-location "${outputPath}"`,
88+
+ "--force"
89+
+ ];
90+
+ if (!openProject) options2.push("--no-open");
91+
+ if (projectType === "ios") options2.push("--ios-only");
92+
+ if (projectType === "macos") options2.push("--macos-only");
93+
+ console.log(`xcrun safari-web-extension-converter ${options2.join(" ")} ${inputPath}`);
94+
+ await $`xcrun safari-web-extension-converter ${options2.join(" ")} ${inputPath}`;
95+
+ wxt2.logger.info(`Updating ${highlight("Xcode project config")}...`);
96+
await updateProjectConfig({
97+
projectName,
98+
+ outputPath,
99+
appCategory,
100+
developmentTeam,
101+
rootPath: wxt2.config.root
102+
});
103+
- wxt2.logger.info("Updating Info.plist files...");
104+
+ wxt2.logger.info(`Updating ${highlight("Info.plist files")}...`);
105+
await updateInfoPlist({
106+
projectName,
107+
+ outputPath,
108+
appCategory,
109+
developmentTeam,
110+
rootPath: wxt2.config.root
111+
@@ -112,6 +133,9 @@ var index_default = defineWxtModule({
112+
});
113+
}
114+
});
115+
+function highlight(text) {
116+
+ return `\x1B[36m${text}\x1B[0m`;
117+
+}
118+
export {
119+
index_default as default
120+
};

pnpm-lock.yaml

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ overrides:
1010

1111
patchedDependencies:
1212
publish-browser-extension: patches/publish-browser-extension.patch
13+
wxt-module-safari-xcode: patches/wxt-module-safari-xcode.patch

wxt.config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { defineConfig } from "wxt";
33
// See https://wxt.dev/api/config.html
44
export default defineConfig({
55
imports: false,
6-
modules: ["@wxt-dev/module-react"],
6+
modules: ["@wxt-dev/module-react", "wxt-module-safari-xcode"],
77
srcDir: "src",
88
webExt: {
99
startUrls: ["https://csstats.gg/player/76561198088629896"],
@@ -18,6 +18,13 @@ export default defineConfig({
1818
edge: "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
1919
},
2020
},
21+
safariXcode: {
22+
appCategory: "public.app-category.utilities",
23+
bundleIdentifier: "fr.juknum.csstats-plus",
24+
developmentTeam: "LJX55H43JB",
25+
outputPath: ".output/safari-xcode",
26+
projectType: "macos",
27+
},
2128
manifest: {
2229
browser_specific_settings: {
2330
gecko: {

0 commit comments

Comments
 (0)