Files
wehub-resource-sync 91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:19 +08:00

115 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Non-interactive bubblewrap project initialiser.
*
* Usage:
* node _bw_init.js <manifest_url> <output_dir> <package_id> \
* [keystore_path [keystore_alias [keystore_password [fetch_url]]]]
*
* manifest_url: The TWA origin URL (used in twa-manifest.json host field).
* fetch_url: Optional URL to fetch the Web App Manifest from (defaults to
* manifest_url). Use this when manifest_url is an
* emulator-internal address like http://10.0.2.2:3000 that is
* not reachable from the host — pass the host-accessible URL
* (e.g. http://127.0.0.1:3000) as fetch_url while keeping
* manifest_url as the in-emulator origin for assetlinks.json.
*/
const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const npmPrefix = execSync('npm root -g').toString().trim();
const BW_CLI = path.join(npmPrefix, '@bubblewrap', 'cli');
const corePath = path.join(BW_CLI, 'node_modules', '@bubblewrap', 'core');
const { TwaManifest } = require(path.join(corePath, 'dist/lib/TwaManifest'));
const [
,
,
manifestUrl,
outputDir,
packageId,
keystorePath,
keystoreAlias,
keystorePassword,
fetchUrl,
] = process.argv;
if (!manifestUrl || !outputDir || !packageId) {
console.error(
'Usage: node _bw_init.js <manifest_url> <output_dir> <package_id> [keystore_path [alias [password [fetch_url]]]]'
);
process.exit(1);
}
const KEYSTORE = keystorePath || path.join(outputDir, 'android.keystore');
const KEYSTORE_ALIAS = keystoreAlias || 'android';
const KEYSTORE_PASS = keystorePassword || 'android';
// If the manifest URL uses an emulator-internal host (10.0.2.2), replace it
// with 127.0.0.1 for fetching from the host machine.
const resolvedFetchUrl =
fetchUrl || manifestUrl.replace('10.0.2.2', '127.0.0.1').replace('10.0.3.2', '127.0.0.1');
(async () => {
try {
console.log(`Fetching web manifest from: ${resolvedFetchUrl}`);
const twa = await TwaManifest.fromWebManifest(resolvedFetchUrl);
// Override host with the in-emulator origin so assetlinks.json is verified
// against the address Chrome will actually use inside the emulator.
const originUrl = new URL(manifestUrl);
twa.packageId = packageId;
twa.host = originUrl.host; // e.g. "cuaai--todo-gym-web.modal.run"
// startUrl comes from Web App Manifest start_url (already parsed by fromWebManifest).
// Do NOT override it with the manifest file path — that would open manifest.json.
twa.manifestUrl = manifestUrl;
twa.signingKey = { path: KEYSTORE, alias: KEYSTORE_ALIAS };
// If the maskable icon is a PNG that 404s but an SVG variant exists,
// fall back to the SVG so bubblewrap update doesn't fail on missing icons.
if (twa.maskableIconUrl && twa.maskableIconUrl.endsWith('.png')) {
try {
const { execFileSync } = require('child_process');
const status = execFileSync(
'curl', ['-s', '-o', '/dev/null', '-w', '%{http_code}', '--', twa.maskableIconUrl],
{ timeout: 10000 }
)
.toString()
.trim();
if (status === '404') {
const svgUrl = twa.maskableIconUrl.replace(/\.png$/, '.svg');
const svgStatus = execFileSync(
'curl', ['-s', '-o', '/dev/null', '-w', '%{http_code}', '--', svgUrl],
{ timeout: 10000 }
)
.toString()
.trim();
if (svgStatus === '200') {
console.log(`Maskable icon PNG 404d, falling back to SVG: ${svgUrl}`);
twa.maskableIconUrl = svgUrl;
}
}
} catch (_) {
// best-effort — ignore curl failures
}
}
const outFile = path.join(outputDir, 'twa-manifest.json');
const json = twa.toJson();
json.signingKey = {
path: KEYSTORE,
alias: KEYSTORE_ALIAS,
keypassword: KEYSTORE_PASS,
password: KEYSTORE_PASS,
};
fs.writeFileSync(outFile, JSON.stringify(json, null, 2));
console.log(`twa-manifest.json written to ${outFile}`);
console.log(` host: ${json.host} package: ${json.packageId}`);
} catch (e) {
console.error('Error:', e.message || e);
process.exit(1);
}
})();