diff --git a/README.md b/README.md index 6900183e..3e053780 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,15 @@ Monorepo containing: - **WASM** - ONNX Runtime and Yoga Layout - **ML Models** - Quantized AI models (CodeT5, MiniLM) +The packages stack into four tiers — native libraries at the bottom, the custom Node.js binary at the top: + +![Build order: native libraries flow up into the final Node.js binary](docs/images/build-tiers.svg) + ## Core Concepts -If you're new to binary manipulation or Node.js customization, here are the key concepts you'll encounter: +If you're new to binary manipulation or Node.js customization, here are the key concepts you'll encounter. The diagram below shows how `binject` merges your app with the Node.js runtime to produce a Single Executable Application — solid borders are real files on disk, dashed borders are virtual files embedded inside the binary: + +![How a Socket binary is built: binject merges the Node.js runtime with your app's source files into a SEA containing a runtime, an SEA blob, and a VFS section](docs/images/binary-anatomy.svg) ### Single Executable Application (SEA) @@ -70,6 +76,12 @@ Reducing binary size for distribution. Compressed binaries self-extract at runti **Example:** 60MB Node.js binary → 23MB compressed binary (saves bandwidth, faster downloads). +### Putting it together: what happens when a user runs the binary + +The stub decompresses the zstd payload, the Node.js runtime boots and reads the SEA blob to find the entry point, and the running app reads VFS files via `fs.readFile()` like they were on disk: + +![Runtime lifecycle: stub decompresses, runtime executes the SEA blob and reads VFS, your app produces output](docs/images/lifecycle.svg) + ## Quick Start `binject` / `binpress` depend on a prebuilt LIEF artifact, and `stubs-builder` depends on prebuilt curl+mbedTLS; both are fetched automatically from this repo's GitHub releases on first build. Pass `pnpm --filter run build -- --force` if you need to compile those libraries from source (e.g. an unsupported platform or a LIEF/curl bump that hasn't been published yet). diff --git a/docs/images/binary-anatomy.svg b/docs/images/binary-anatomy.svg new file mode 100644 index 00000000..3e35d225 --- /dev/null +++ b/docs/images/binary-anatomy.svg @@ -0,0 +1,101 @@ + + How a Socket binary is built + binject merges a Node.js runtime with your app's source files into a Single Executable Application. Solid borders are real files on disk; dashed borders are virtual files embedded inside the binary. + + + + + + + + + + + + + + + + + + + + + + How a Socket binary is built + binject merges the Node.js runtime with your app's files into one Single Executable Application. + + + INPUTS · ON DISK + + + Node.js binary + raw, no app yet + from node-smol-builder + + + + + + your app + files + + + index.js + + + sea-config.json + + + node_modules/ + + + assets/icon.png + + …and any other files + + + + binject + compiles entry → SEA blob + tars files → VFS section + injects both into the binary + + + OUTPUT · ONE BINARY + + + Single Executable Application (SEA) + + + + Node.js runtime + v26 + Socket patches · node:smol-* built-ins + + + SEA BLOB · executed on startup + + index.js (bytecode) + + sea-config.json + + + VFS SECTION · read via fs.readFile() + + package.json + + node_modules/ + + assets/ + + + lib/util.js + + templates/ + + + + these look like real files to your code · fs.readFile('package.json') just works + stored as a tar.gz · ungzipped lazily by node:smol-vfs + + + Legend: solid borders = real files on disk · dashed borders = virtual files embedded inside the binary. + diff --git a/docs/images/build-tiers.svg b/docs/images/build-tiers.svg new file mode 100644 index 00000000..ae2a12a6 --- /dev/null +++ b/docs/images/build-tiers.svg @@ -0,0 +1,64 @@ + + Socket BTM build order + Four tiers of packages stacked vertically. Native libraries (curl, LIEF) at the bottom, custom Node.js binary at the top. Re-publishing any tier requires re-publishing every tier above it. + + + + + + + + + + + Build Order + Native libraries at the bottom, custom Node.js at the top. + Re-publishing any tier cascades upward — every tier above it must republish too. + + + TIER 4 · CUSTOM NODE.JS + + + node-smol-builder + Node.js v26 + Socket security patches + node:smol-* built-ins · VFS · SEA + + + + TIER 3 · BINARY SUITE + + + binject + inject data into binaries + + + binpress + zstd compress + + + binflate + decompress at runtime + + + + TIER 2 · STUBS + + + stubs-builder + self-extracting stub binary + + + + TIER 1 · NATIVE LIBRARIES + + + curl-builder + libcurl + mbedTLS + + + lief-builder + LIEF · Mach-O / ELF / PE + + + Skipping a tier or dispatching out of order is gated by scripts/check-publish-prereq.mts. + diff --git a/docs/images/lifecycle.svg b/docs/images/lifecycle.svg new file mode 100644 index 00000000..7682afc0 --- /dev/null +++ b/docs/images/lifecycle.svg @@ -0,0 +1,76 @@ + + What happens when you run a Socket binary + Three stages: the stub unpacks the compressed binary, the Node.js runtime boots and reads the SEA blob and VFS, and your app produces output. + + + + + + + + + + + + + + + + + + + + + + + + + + What happens when you run a Socket binary + Three stages: the stub unpacks, the runtime boots, your app produces output. + + + 1 · ON DISK + + compressed binary + ~23 MB · what the user downloads + + + stub + + + zstd payload + + + + stub: zstd-decompress + exec inner binary + + + 2 · IN MEMORY · THE SEA + + Single Executable Application + + + Node.js runtime · v26 + Socket patches + + + SEA blob (entry bytecode + config) + + + VFS section (embedded files) + + runtime boots · reads SEA blob to find the entry · serves VFS to fs.readFile() + + + + runtime executes the entry · your app code runs + + + 3 · ✨ OUTPUT + + your app's output + scan complete · 0 critical · 2 medium + whatever your CLI prints + + +