Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ node_modules
.decrypt
.capy-sync
dist
build
bin-pkg
.capy-token
*.env
.capy
71 changes: 71 additions & 0 deletions build.esbuild.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Bundles the CLI into a single CommonJS file ready to be wrapped by @yao-pkg/pkg.
// Mirrors dotenvx's pattern: emit build/index.cjs + a stripped build/package.json
// whose `pkg` block is what @yao-pkg/pkg actually consumes.
import { build } from 'esbuild';
import { mkdir, rm, stat, writeFile, readFile } from 'fs/promises';
import { fileURLToPath } from 'url';
import path from 'path';

const here = path.dirname(fileURLToPath(import.meta.url));
const outDir = path.join(here, 'build');
const outFile = path.join(outDir, 'index.cjs');

async function emptyDir(dir) {
await rm(dir, { recursive: true, force: true });
await mkdir(dir, { recursive: true });
}

async function printSize(file) {
const { size } = await stat(file);
console.log(`Bundle: ${(size / 1024 / 1024).toFixed(2)} MB`);
}

async function main() {
const pkgJson = JSON.parse(await readFile(path.join(here, 'package.json'), 'utf8'));

await emptyDir(outDir);

await build({
entryPoints: [path.join(here, 'src/index.ts')],
bundle: true,
platform: 'node',
target: 'node20',
format: 'cjs',
outfile: outFile,
sourcemap: false,
minify: false,
legalComments: 'none',
logOverride: { 'direct-eval': 'silent' },
define: {
'process.env.CAPY_CLI_VERSION': JSON.stringify(pkgJson.version),
},
});

await printSize(outFile);

// Stripped manifest for pkg. pkg reads `bin` + `pkg` from this manifest.
const stripped = {
name: pkgJson.name,
version: pkgJson.version,
description: pkgJson.description,
license: pkgJson.license,
bin: 'index.cjs',
main: 'index.cjs',
pkg: {
scripts: ['index.cjs'],
assets: [],
},
};

await writeFile(
path.join(outDir, 'package.json'),
JSON.stringify(stripped, null, 2) + '\n',
);

console.log(`Wrote ${outFile} and ${path.join(outDir, 'package.json')}`);
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"test": "bash tests/run-tests.sh",
"typecheck": "tsc --noEmit",
"test:e2e": "bun run tests/e2e/e2e.ts",
"clean": "rm -rf dist"
"clean": "rm -rf dist build bin-pkg",
"bundle": "node build.esbuild.mjs",
"build:binary": "node scripts/build-binary.mjs"
},
"dependencies": {
"@capy/sdk": "workspace:*",
Expand All @@ -39,6 +41,8 @@
"@types/inquirer": "^9.0.0",
"@types/node": "^20.0.0",
"@types/proper-lockfile": "^4.1.4",
"@yao-pkg/pkg": "^6.14.2",
"esbuild": "^0.25.8",
"typescript": "^5.0.0"
},
"license": "AGPL-3.0-only",
Expand Down
59 changes: 59 additions & 0 deletions scripts/build-binary.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Local-dev driver: bundle with esbuild then wrap with @yao-pkg/pkg for the
// host platform only. CI uses .github/workflows/release.yml for the full
// cross-compile matrix.
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import path from 'path';

const here = path.dirname(fileURLToPath(import.meta.url));
const cliDir = path.resolve(here, '..');

function run(cmd, args, opts = {}) {
return new Promise((resolve, reject) => {
const child = spawn(cmd, args, { stdio: 'inherit', ...opts });
child.on('exit', (code) =>
code === 0 ? resolve() : reject(new Error(`${cmd} exited ${code}`)),
);
});
}

function hostTarget() {
const { platform, arch } = process;
const archMap = { x64: 'x64', arm64: 'arm64' };
const a = archMap[arch];
if (!a) throw new Error(`Unsupported host arch: ${arch}`);
if (platform === 'darwin') return `node20-macos-${a}`;
if (platform === 'linux') return `node20-linuxstatic-${a}`;
if (platform === 'win32') return `node20-win-${a}`;
throw new Error(`Unsupported host platform: ${platform}`);
}

async function main() {
const target = process.env.PKG_TARGET || hostTarget();
const outName = process.platform === 'win32' ? 'capy.exe' : 'capy';
const outPath = path.join(cliDir, 'bin-pkg', outName);

await run('node', [path.join(cliDir, 'build.esbuild.mjs')], { cwd: cliDir });
await run(
'bunx',
[
'@yao-pkg/pkg',
'.',
'--public-packages',
'*',
'--public',
'--target',
target,
'--output',
outPath,
],
{ cwd: path.join(cliDir, 'build') },
);

console.log(`\nBinary: ${outPath} (target ${target})`);
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
Loading