Files
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

169 lines
5.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Bundles happy-server into a self-contained artifact directory.
*
* Uses `bun build --compile` to produce a single platform-specific binary, then copies the
* pglite WASM/data files and prisma migrations alongside. happy-cli does NOT depend on the
* happy-server workspace package — we reach into the sibling directory at build time only.
*
* Layout produced:
* <out-dir>/
* <platform>/
* happy-server # bun-compiled binary
* pglite.wasm # PGlite expects these next to process.execPath
* pglite.data
* prisma/migrations/...
*
* Prisma query engine: bun --compile cannot embed native .node modules. The package
* that runs this binary must provide @prisma/engines and point Prisma at the native
* library for the current machine via PRISMA_QUERY_ENGINE_LIBRARY.
*
* Default: builds for the current host platform only. Pass --all-platforms to cross-build
* for every supported platform (used by release/CI).
*/
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const { spawnSync } = require('node:child_process');
const PACKAGE_DIR = path.resolve(__dirname, '..');
const REPO_ROOT = path.resolve(PACKAGE_DIR, '..', '..');
const SERVER_DIR = path.resolve(REPO_ROOT, 'packages/happy-server');
const BUN_TARGETS = {
'arm64-darwin': 'bun-darwin-arm64',
'x64-darwin': 'bun-darwin-x64',
'arm64-linux': 'bun-linux-arm64',
'x64-linux': 'bun-linux-x64',
'x64-win32': 'bun-windows-x64',
};
function currentPlatform() {
const platform = os.platform();
const arch = os.arch();
return `${arch}-${platform}`;
}
function platformBinaryName(plat) {
return plat.endsWith('-win32') ? 'happy-server.exe' : 'happy-server';
}
function run(cmd, args, opts = {}) {
console.log(` $ ${cmd} ${args.join(' ')}`);
const result = spawnSync(cmd, args, { stdio: 'inherit', ...opts });
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
}
function rmrf(p) {
fs.rmSync(p, { recursive: true, force: true });
}
function copyDir(src, dst) {
fs.cpSync(src, dst, { recursive: true });
}
function findPgliteAsset(name) {
const candidates = [
path.join(REPO_ROOT, 'node_modules/@electric-sql/pglite/dist', name),
path.join(SERVER_DIR, 'node_modules/@electric-sql/pglite/dist', name),
];
for (const c of candidates) {
if (fs.existsSync(c)) return c;
}
return null;
}
function buildPlatform(plat, outRoot) {
if (!BUN_TARGETS[plat]) {
console.error(`Unsupported platform: ${plat}`);
process.exit(1);
}
const target = BUN_TARGETS[plat];
const outDir = path.join(outRoot, plat);
fs.mkdirSync(outDir, { recursive: true });
const outFile = path.join(outDir, platformBinaryName(plat));
console.log(`\n→ Bundling happy-server for ${plat} (${target})`);
run(
'bun',
[
'build',
'./sources/standalone.ts',
'--compile',
'--outfile',
outFile,
'--target',
target,
// optional peer deps we don't bundle (only relevant when running against external redis)
'--external',
'redis',
'--external',
'@prisma/engines',
'--external',
'prisma',
],
{ cwd: SERVER_DIR }
);
}
function copyAssetsForPlatform(plat, outRoot) {
const platDir = path.join(outRoot, plat);
console.log(`\n→ Copying assets (pglite + migrations) into ${path.relative(PACKAGE_DIR, platDir)}`);
for (const asset of ['pglite.wasm', 'pglite.data']) {
const src = findPgliteAsset(asset);
if (!src) {
console.error(`Could not find ${asset} in @electric-sql/pglite/dist`);
process.exit(1);
}
fs.copyFileSync(src, path.join(platDir, asset));
console.log(` copied ${asset}`);
}
const migrationsSrc = path.join(SERVER_DIR, 'prisma/migrations');
const migrationsDst = path.join(platDir, 'prisma/migrations');
fs.mkdirSync(path.dirname(migrationsDst), { recursive: true });
copyDir(migrationsSrc, migrationsDst);
console.log(` copied prisma/migrations`);
}
function main() {
const args = process.argv.slice(2);
const allPlatforms = args.includes('--all-platforms');
const outDirArg = valueAfter(args, '--out-dir');
const outDir = outDirArg ? path.resolve(process.cwd(), outDirArg) : path.resolve(PACKAGE_DIR, 'tools/server');
if (!fs.existsSync(SERVER_DIR)) {
console.error(`Missing ${SERVER_DIR}. Run from the monorepo.`);
process.exit(1);
}
rmrf(outDir);
fs.mkdirSync(outDir, { recursive: true });
const targets = allPlatforms ? Object.keys(BUN_TARGETS) : [currentPlatform()];
for (const plat of targets) {
buildPlatform(plat, outDir);
copyAssetsForPlatform(plat, outDir);
}
console.log(`\n✓ happy-server bundle written to ${outDir}`);
}
function valueAfter(args, flag) {
const idx = args.indexOf(flag);
if (idx === -1) return null;
const value = args[idx + 1];
if (!value || value.startsWith('--')) {
console.error(`Missing value for ${flag}`);
process.exit(1);
}
return value;
}
main();