@mirinjs/cli 0.0.1-alpha.12 → 0.0.1-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/bundle.ts +59 -7
- package/src/release.ts +23 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirinjs/cli",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.13",
|
|
4
4
|
"description": "CLI for mirin apps: dev, build, init.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"bun": ">=1.2.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"create-mirinjs": "0.0.1-alpha.
|
|
31
|
-
"mirinjs": "0.0.1-alpha.
|
|
30
|
+
"create-mirinjs": "0.0.1-alpha.13",
|
|
31
|
+
"mirinjs": "0.0.1-alpha.13"
|
|
32
32
|
},
|
|
33
33
|
"optionalDependencies": {
|
|
34
|
-
"@mirinjs/darwin-arm64": "0.0.1-alpha.
|
|
34
|
+
"@mirinjs/darwin-arm64": "0.0.1-alpha.13"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
package/src/bundle.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { $ } from "bun";
|
|
15
|
-
import { cpSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
|
|
15
|
+
import { cpSync, mkdirSync, rmSync, writeFileSync, existsSync, readdirSync } from "node:fs";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
|
|
18
18
|
const FRAMEWORK = "Chromium Embedded Framework.framework";
|
|
@@ -208,14 +208,66 @@ export async function buildAppBundle(opts: BundleOptions): Promise<{ app: string
|
|
|
208
208
|
);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
// Sign inside-out
|
|
212
|
-
//
|
|
211
|
+
// Sign inside-out. Ad-hoc ("-") by default for local builds; pass a Developer
|
|
212
|
+
// ID to produce a distributable, notarizable app. Notarization requires the
|
|
213
|
+
// hardened runtime (--options runtime), a secure timestamp (--timestamp), and
|
|
214
|
+
// entitlements that let CEF + Bun JIT and load unsigned executable memory —
|
|
215
|
+
// without all three the Apple notary service returns "Invalid".
|
|
213
216
|
const identity = opts.signIdentity ?? "-";
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
const notarizable = identity !== "-";
|
|
218
|
+
const cef = join(frameworks, FRAMEWORK);
|
|
219
|
+
|
|
220
|
+
if (notarizable) {
|
|
221
|
+
// Mirrors the entitlement set Electrobun ships for Bun + CEF under hardened
|
|
222
|
+
// runtime (electrobun-reference/package/src/cli/index.ts).
|
|
223
|
+
const entitlements = join(opts.outDir, "_entitlements.plist");
|
|
224
|
+
writeFileSync(
|
|
225
|
+
entitlements,
|
|
226
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
227
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
228
|
+
<plist version="1.0">
|
|
229
|
+
<dict>
|
|
230
|
+
<key>com.apple.security.cs.allow-jit</key><true/>
|
|
231
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
|
|
232
|
+
<key>com.apple.security.cs.disable-library-validation</key><true/>
|
|
233
|
+
</dict>
|
|
234
|
+
</plist>
|
|
235
|
+
`,
|
|
236
|
+
);
|
|
237
|
+
const sign = (path: string, ents = false) =>
|
|
238
|
+
ents
|
|
239
|
+
? $`codesign --force --timestamp --options runtime --entitlements ${entitlements} --sign ${identity} ${path}`.quiet()
|
|
240
|
+
: $`codesign --force --timestamp --options runtime --sign ${identity} ${path}`.quiet();
|
|
241
|
+
|
|
242
|
+
// 1. CEF's nested libraries, then 2. the framework bundle itself.
|
|
243
|
+
const cefLibs = join(cef, "Libraries");
|
|
244
|
+
if (existsSync(cefLibs)) {
|
|
245
|
+
for (const lib of readdirSync(cefLibs)) {
|
|
246
|
+
if (lib.endsWith(".dylib")) await sign(join(cefLibs, lib));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
await sign(cef);
|
|
250
|
+
// 3. our FFI core dylib.
|
|
251
|
+
await sign(join(macos, "libmirin_core.dylib"));
|
|
252
|
+
// 4. each helper: the inner executable, then the .app wrapper (entitlements
|
|
253
|
+
// on both — the renderer/GPU helpers are what actually JIT).
|
|
254
|
+
for (const { suffix } of HELPER_TYPES) {
|
|
255
|
+
const name = `${appName} Helper${suffix}`;
|
|
256
|
+
const helperApp = join(frameworks, `${name}.app`);
|
|
257
|
+
await sign(join(helperApp, "Contents", "MacOS", name), true);
|
|
258
|
+
await sign(helperApp, true);
|
|
259
|
+
}
|
|
260
|
+
// 5. finally the outer app.
|
|
261
|
+
await sign(app, true);
|
|
262
|
+
rmSync(entitlements, { force: true });
|
|
263
|
+
} else {
|
|
264
|
+
// Ad-hoc: enough to launch locally; not distributable or notarizable.
|
|
265
|
+
await $`codesign --force --sign ${identity} ${cef}`.quiet();
|
|
266
|
+
for (const { suffix } of HELPER_TYPES) {
|
|
267
|
+
await $`codesign --force --sign ${identity} ${join(frameworks, `${appName} Helper${suffix}.app`)}`.quiet();
|
|
268
|
+
}
|
|
269
|
+
await $`codesign --force --sign ${identity} ${app}`.quiet();
|
|
217
270
|
}
|
|
218
|
-
await $`codesign --force --sign ${identity} ${app}`.quiet();
|
|
219
271
|
|
|
220
272
|
return { app, exe: join(macos, appName) };
|
|
221
273
|
}
|
package/src/release.ts
CHANGED
|
@@ -52,9 +52,30 @@ export async function release(projectDir = process.cwd()): Promise<number> {
|
|
|
52
52
|
console.log("[mirin release] notarizing (this can take a few minutes)…");
|
|
53
53
|
const zip = join(buildDir, "_notarize.zip");
|
|
54
54
|
await $`ditto -c -k --keepParent ${result.app} ${zip}`;
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// `notarytool submit --wait` exits 0 even when the result is "Invalid", so
|
|
56
|
+
// parse the JSON status ourselves and surface the notary log on rejection —
|
|
57
|
+
// otherwise the only symptom is a confusing `stapler` failure downstream.
|
|
58
|
+
const out =
|
|
59
|
+
await $`xcrun notarytool submit ${zip} --apple-id ${apple} --password ${pw} --team-id ${team} --wait --output-format json`.text();
|
|
57
60
|
rmSync(zip, { force: true });
|
|
61
|
+
let sub: { id?: string; status?: string } = {};
|
|
62
|
+
try {
|
|
63
|
+
sub = JSON.parse(out);
|
|
64
|
+
} catch {
|
|
65
|
+
console.error(out);
|
|
66
|
+
}
|
|
67
|
+
if (sub.status !== "Accepted") {
|
|
68
|
+
console.error(`[mirin release] notarization ${sub.status ?? "failed"} (id: ${sub.id ?? "?"})`);
|
|
69
|
+
if (sub.id) {
|
|
70
|
+
const log =
|
|
71
|
+
await $`xcrun notarytool log ${sub.id} --apple-id ${apple} --password ${pw} --team-id ${team}`
|
|
72
|
+
.text()
|
|
73
|
+
.catch(() => "");
|
|
74
|
+
if (log) console.error(log);
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`notarization not accepted: ${sub.status ?? "unknown"}`);
|
|
77
|
+
}
|
|
78
|
+
await $`xcrun stapler staple ${result.app}`;
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
const codec = loadCodec(result.coreDylib);
|