one
Version:
One is a React framework for web, iOS, and Android apps.
310 lines (308 loc) • 12.3 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var updatesPublish_exports = {};
__export(updatesPublish_exports, { runUpdatesPublish: () => runUpdatesPublish });
module.exports = __toCommonJS(updatesPublish_exports);
var import_child_process = require("child_process");
var import_crypto = require("crypto");
var import_fs = require("fs");
var import_module = require("module");
var import_os = require("os");
var import_path = require("path");
var import_appManifest = require("../native/appManifest.native.js");
var import_loadConfig = require("../vite/loadConfig.native.js");
function lastValue(value) {
return Array.isArray(value) ? value[value.length - 1] : value;
}
function allValues(value) {
if (value === void 0) return [];
return Array.isArray(value) ? value : [value];
}
function base64Url(bytes) {
return bytes.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function sha256Base64Url(path) {
return base64Url((0, import_crypto.createHash)("sha256").update((0, import_fs.readFileSync)(path)).digest());
}
function parseMetadata(entries) {
var metadata = {};
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
try {
for (var _iterator = entries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var entry = _step.value;
var equals = entry.indexOf("=");
if (equals <= 0) {
throw new Error(`[one] --metadata must look like key=value, got "${entry}"`);
}
var key = entry.slice(0, equals);
var raw = entry.slice(equals + 1);
var value = raw;
try {
var parsed = JSON.parse(raw);
if (typeof parsed === "string" || typeof parsed === "number" || typeof parsed === "boolean") {
value = parsed;
}
} catch (unused) {}
metadata[key] = value;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return metadata;
}
function collectFiles(root) {
var files = [];
var visit = function visit1(dir) {
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
try {
for (var _iterator = (0, import_fs.readdirSync)(dir, { withFileTypes: true })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var entry = _step.value;
var path = (0, import_path.join)(dir, entry.name);
if (entry.isDirectory()) visit(path);
else if (entry.isFile()) files.push(path);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
};
if ((0, import_fs.existsSync)(root)) visit(root);
return files.sort();
}
function resolveCliJs(root) {
var require2 = (0, import_module.createRequire)((0, import_path.join)(root, "package.json"));
var packageJson = require2.resolve("react-native/package.json");
return (0, import_path.join)(packageJson.slice(0, -"package.json".length), "cli.js");
}
function resolveNpmHermesc(root) {
var require2 = (0, import_module.createRequire)((0, import_path.join)(root, "package.json"));
var reactNativeJson = require2.resolve("react-native/package.json");
var nested = (0, import_module.createRequire)(reactNativeJson);
var compilerJson = nested.resolve("hermes-compiler/package.json");
var dir = compilerJson.slice(0, -"package.json".length);
var bin = process.platform === "darwin" ? "osx-bin" : process.platform === "win32" ? "win64-bin" : "linux64-bin";
return (0, import_path.join)(dir, "hermesc", bin, process.platform === "win32" ? "hermesc.exe" : "hermesc");
}
function resolveHermesc(root, platform) {
if (platform === "ios") {
var pod = (0, import_path.join)(root, "ios", "Pods", "hermes-engine", "destroot", "bin", "hermesc");
if ((0, import_fs.existsSync)(pod)) return pod;
}
var npm = resolveNpmHermesc(root);
if (!(0, import_fs.existsSync)(npm)) {
throw new Error(`[one] hermesc not found at ${npm}: install dependencies${platform === "ios" ? " and run one prebuild with pod install" : ""} first`);
}
return npm;
}
async function resolveRuntimeVersion(platform, flag) {
var _app_updates;
var { oneOptions } = await (0, import_loadConfig.loadUserOneOptions)("build", true);
var native = oneOptions === null || oneOptions === void 0 ? void 0 : oneOptions.native;
var app = typeof native === "object" ? native.app : void 0;
if (!app) {
if (!flag) {
throw new Error("[one] one updates publish needs native.app.updates.runtimeVersion, or --runtime-version for an app built with expo prebuild: the binary only takes updates published for its own runtime version");
}
return flag;
}
(0, import_appManifest.validateNativeApp)(app, platform);
var runtimeVersion = (_app_updates = app.updates) === null || _app_updates === void 0 ? void 0 : _app_updates.runtimeVersion;
if (!runtimeVersion) {
throw new Error("[one] one updates publish needs native.app.updates.runtimeVersion: the binary only takes updates published for its own runtime version");
}
if (flag !== void 0 && flag !== runtimeVersion) {
throw new Error(`[one] --runtime-version ${flag} differs from native.app.updates.runtimeVersion ${runtimeVersion}`);
}
return runtimeVersion;
}
async function runUpdatesPublish(args) {
var platform = lastValue(args.platform);
if (platform !== "ios" && platform !== "android") {
throw new Error("[one] one updates publish needs --platform ios|android");
}
var out = lastValue(args.out);
if (!out) {
throw new Error("[one] one updates publish needs --out <dir>");
}
var intermediatesOut = lastValue(args.intermediatesOut);
if (intermediatesOut) {
var published = (0, import_path.resolve)(out);
var debug = (0, import_path.resolve)(intermediatesOut);
if (published === debug || published.startsWith(`${debug}${import_path.sep}`) || debug.startsWith(`${published}${import_path.sep}`)) {
throw new Error("[one] --intermediates-out must be separate from --out");
}
if ((0, import_fs.existsSync)(debug) && (0, import_fs.readdirSync)(debug).length > 0) {
throw new Error(`[one] refusing to write intermediates into non-empty ${debug}`);
}
}
var root = process.cwd();
var runtimeVersion = await resolveRuntimeVersion(platform, lastValue(args.runtimeVersion));
if ((0, import_fs.existsSync)(out) && (0, import_fs.readdirSync)(out).length > 0) {
throw new Error(`[one] refusing to publish into non-empty ${out}: every publish writes a fresh directory`);
}
(0, import_fs.mkdirSync)(out, { recursive: true });
if (intermediatesOut) {
(0, import_fs.mkdirSync)(intermediatesOut, { recursive: true });
var published1 = (0, import_fs.realpathSync)(out);
var debug1 = (0, import_fs.realpathSync)(intermediatesOut);
if (published1 === debug1 || published1.startsWith(`${debug1}${import_path.sep}`) || debug1.startsWith(`${published1}${import_path.sep}`)) {
throw new Error("[one] --intermediates-out must be separate from --out");
}
}
var assetsOut = (0, import_path.join)(out, "assets");
(0, import_fs.mkdirSync)(assetsOut, { recursive: true });
var metadata = parseMetadata(allValues(args.metadata));
var work = (0, import_fs.mkdtempSync)((0, import_path.join)((0, import_os.tmpdir)(), "one-updates-publish-"));
var bundleJs = (0, import_path.join)(work, "bundle.js");
var packagerMap = (0, import_path.join)(work, "bundle.js.map");
var assetsDir = (0, import_path.join)(work, "assets");
var bytecode = (0, import_path.join)(work, "main.jsbundle");
var composedMap = (0, import_path.join)(work, "main.jsbundle.map");
try {
(0, import_child_process.execFileSync)(process.execPath, [
resolveCliJs(root),
"bundle",
"--entry-file",
"index.js",
"--platform",
platform,
"--dev",
"false",
"--reset-cache",
"--bundle-output",
bundleJs,
...intermediatesOut ? ["--sourcemap-output", packagerMap] : [],
"--assets-dest",
assetsDir,
"--minify",
platform === "ios" ? "true" : "false"
], {
cwd: root,
stdio: "inherit"
});
var hermesc = resolveHermesc(root, platform);
var hermescArgs = ["-emit-binary", "-max-diagnostic-width=80"];
if (platform === "android") hermescArgs.push("-w");
hermescArgs.push("-O");
if (intermediatesOut) hermescArgs.push("-output-source-map");
hermescArgs.push("-out", bytecode, bundleJs);
try {
(0, import_child_process.execFileSync)(hermesc, hermescArgs, {
cwd: root,
stdio: "inherit"
});
} catch (error) {
throw new Error(`[one] hermesc failed to compile the ${platform} update bundle${error instanceof Error ? `: ${error.message}` : ""}`);
}
if (intermediatesOut) {
var require2 = (0, import_module.createRequire)((0, import_path.join)(root, "package.json"));
var reactNativeJson = require2.resolve("react-native/package.json");
var composeSourceMaps = (0, import_path.join)(reactNativeJson.slice(0, -"package.json".length), "scripts", "compose-source-maps.js");
(0, import_child_process.execFileSync)(process.execPath, [
composeSourceMaps,
packagerMap,
`${bytecode}.map`,
"-o",
composedMap
], {
cwd: root,
stdio: "inherit"
});
(0, import_fs.writeFileSync)((0, import_path.join)(intermediatesOut, "bundle.js"), (0, import_fs.readFileSync)(bundleJs));
(0, import_fs.writeFileSync)((0, import_path.join)(intermediatesOut, "main.jsbundle.map"), (0, import_fs.readFileSync)(composedMap));
}
var bundleHash = sha256Base64Url(bytecode);
(0, import_fs.writeFileSync)((0, import_path.join)(assetsOut, bundleHash), (0, import_fs.readFileSync)(bytecode));
var assets = [];
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
try {
for (var _iterator = collectFiles(assetsDir)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var file = _step.value;
var hash = sha256Base64Url(file);
var target = (0, import_path.join)(assetsOut, hash);
if (!(0, import_fs.existsSync)(target)) (0, import_fs.writeFileSync)(target, (0, import_fs.readFileSync)(file));
assets.push({
hash,
url: `assets/${hash}`,
path: (0, import_path.relative)(assetsDir, file).split(import_path.sep).join("/")
});
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
assets.sort(function(a, b) {
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
});
var manifest = {
id: (0, import_crypto.randomUUID)(),
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
runtimeVersion,
launchAsset: {
hash: bundleHash,
url: `assets/${bundleHash}`,
path: "main.jsbundle"
},
assets,
metadata
};
(0, import_fs.writeFileSync)((0, import_path.join)(out, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
`);
console.info(`[one] published ${platform} update ${manifest.id} (${assets.length} assets) to ${out}`);
} finally {
(0, import_fs.rmSync)(work, {
recursive: true,
force: true
});
}
}