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
169 lines
5.2 KiB
JavaScript
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();
|