From cb808bfae9005ce614ea810acec1cd12db699a6a Mon Sep 17 00:00:00 2001 From: Kalleby Santos Date: Thu, 16 Apr 2026 20:14:10 +0100 Subject: [PATCH 1/3] feat: building egde-runtime with nix --- flake.lock | 60 +++++++++++ flake.nix | 16 +++ nix/edge-runtime.nix | 241 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/edge-runtime.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..186b012c --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1776361032, + "narHash": "sha256-Sg6Y1N7DwlHsk0Sq5HialITmRNvtZud+Ew9epPMxdNY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3ffdb960eea94b6eeef63eac8df173464aa3f145", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..de94b08f --- /dev/null +++ b/flake.nix @@ -0,0 +1,16 @@ +{ + description = "Supabase Edge Runtime"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in { + packages.edge-runtime = pkgs.callPackage ./nix/edge-runtime.nix { }; + defaultPackage = self.packages.${system}.edge-runtime; + }); +} + diff --git a/nix/edge-runtime.nix b/nix/edge-runtime.nix new file mode 100644 index 00000000..fa490c9d --- /dev/null +++ b/nix/edge-runtime.nix @@ -0,0 +1,241 @@ +{ + lib, + stdenv, + rustPlatform, + openblas, + onnxruntime, + pkg-config, + patchelf, + curl, + fetchurl, + cmake, +}: +let + build_step = rustPlatform.buildRustPackage (finalAttrs: { + pname = "edge_runtime_build"; + version = "v1.73.3"; + src = ../.; + cargoLock = { + lockFile = ../Cargo.lock; + outputHashes = { + "deno_core-0.324.0" = "sha256-WCEUKkCnDQ3VHILsf1hAnz1L1wlr9prTMgHKnzJ5cXc="; + "v8-130.0.7" = "sha256-0mcHKmIECFX7yTTOh0yEjyCMXCkwxL5LS1TkuO8GTlA="; + "eszip-0.80.0" = "sha256-KILUDqMpMbR9WuB7gE0a4kiRECVB2dTiOW++3sz2mBU="; + }; + }; + + RUSTY_V8_MIRROR="null"; + RUST_BACKTRACE=1; + RUSTY_V8_SRC_BINDING_PATH = fetchurl { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_aarch64-apple-darwin.rs"; + sha256 = "sha256-ytcUCd4V1MQkinakmT3rJsdow1RLVWrGqtMjava4BaU="; + }; + RUSTY_V8_ARCHIVE= fetchurl { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/librusty_v8_release_aarch64-apple-darwin.a.gz"; + sha256 = "sha256-VYWg+9WekcHBJWEq49eAAVpc6g/PPaoZDm/j2DKNQLY="; + }; + DYLD_LIBRARY_PATH = "${onnxruntime}/lib"; + + nativeBuildInputs = [ pkg-config curl cmake ]; + buildInputs = [ openblas onnxruntime ]; + propagatedBuildInputs = [ onnxruntime ]; + doCheck = false; + }); +in +stdenv.mkDerivation { + name = "edge_runtime_portable"; + version = "0.1.0"; + dontUnpack = true; + dontPatchShebangs = true; + nativeBuildInputs = lib.optionals stdenv.isLinux [ patchelf ]; + +buildPhase = '' + mkdir -p $out/bin $out/lib + + binaries="edge-runtime" + + get_deps() { + if [ "$(uname)" = "Darwin" ]; then + otool -L "$1" 2>/dev/null | grep /nix/store | awk '{print $1}' + else + ldd "$1" 2>/dev/null | grep /nix/store | awk '{print $3}' + fi + } + + # Helper function to check if a library should be excluded (system libraries) + should_exclude() { + local libname="$1" + # Exclude core system libraries that must come from the host system + # These libraries are tightly coupled to the kernel and system configuration + case "$libname" in + libc.so*|libc-*.so*|ld-linux*.so*|libdl.so*|libpthread.so*|libm.so*|libresolv.so*|librt.so*) + return 0 # Exclude + ;; + *) + return 1 # Include + ;; + esac + } + + # Helper function to get dependencies from a binary based on platform + # Returns empty string if no dependencies found (which is valid - not an error) + copy_dep() { + local dep="$1" + local libname=$(basename "$dep") + [ -f "$out/lib/$libname" ] && return # already copied + should_exclude "$libname" && return + [ -f "$dep" ] && cp "$dep" $out/lib/ 2>/dev/null || true + } + + # Helper function to get the library file pattern based on platform + get_lib_pattern() { + if [ "$(uname)" = "Darwin" ]; then + echo "*.dylib*" + else + echo "*.so*" + fi + } + + # Copy binaries from cargo build to wrapped style + for bin in $binaries; do + cp ${build_step}/bin/$bin $out/bin/.$bin-wrapped 2>/dev/null || true + done + + # Seed: direct deps of binary + onnxruntime and all its siblings + for dep in $(get_deps $out/bin/.*-wrapped); do + copy_dep "$dep" + done + + # Copy onnxruntime + lib_pattern=$(get_lib_pattern) + cp ${onnxruntime}/lib/libonnxruntime$lib_pattern $out/lib/ 2>/dev/null || true + + # Iterative crawl until no new deps appear + for iteration in {1..5}; do + before_count=$(ls $out/lib/ | wc -l || echo "0") + + for lib in $out/lib/*; do + [ -f "$lib" ] || continue + for dep in $(get_deps "$lib"); do + copy_dep "$dep" + done + done + + after=$(ls $out/lib/ | wc -l) + echo "Iteration $iteration: $before_count -> $after libs" + [ "$before_count" -eq "$after" ] && break + done +''; + +installPhase = '' + # Create wrapper scripts and set up library paths + for bin in $binaries; do + if [ -f $out/bin/.$bin-wrapped ]; then + cat > $out/bin/$bin << 'WRAPPER_EOF' +#!/bin/sh +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +LIB_DIR="$SCRIPT_DIR/../lib" + +# For Linux, set LD_LIBRARY_PATH to include bundled libraries +if [ "$(uname)" = "Linux" ]; then + export LD_LIBRARY_PATH="$LIB_DIR''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +fi + +# For macOS, set DYLD_LIBRARY_PATH +if [ "$(uname)" = "Darwin" ]; then + export DYLD_LIBRARY_PATH="$LIB_DIR''${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}" +fi + +exec "$SCRIPT_DIR/.BINNAME-wrapped" "$@" +WRAPPER_EOF + sed -i "s/BINNAME/$bin/g" $out/bin/$bin + chmod +x $out/bin/$bin + fi + done +''; + + postFixup = + lib.optionalString stdenv.isLinux '' + # Determine the correct interpreter path based on architecture + if [ "$(uname -m)" = "x86_64" ]; then + INTERP="/lib64/ld-linux-x86-64.so.2" + elif [ "$(uname -m)" = "aarch64" ]; then + INTERP="/lib/ld-linux-aarch64.so.1" + else + echo "ERROR: Unsupported architecture $(uname -m)" + exit 1 + fi + + # On Linux, patch binaries to use system interpreter and relative library paths + # This makes the bundle portable across Linux systems + for bin in $out/bin/.*-wrapped; do + if [ -f "$bin" ] && file "$bin" | grep -q ELF; then + echo "Patching RPATH and interpreter for $bin" + # Set interpreter to system dynamic linker for portability + patchelf --set-interpreter "$INTERP" "$bin" 2>/dev/null || true + # Set RPATH to $ORIGIN/../lib so binaries find libraries relative to their location + patchelf --set-rpath '$ORIGIN/../lib' "$bin" 2>/dev/null || true + # Shrink RPATH to remove any unused paths + patchelf --shrink-rpath "$bin" 2>/dev/null || true + fi + done + + # Patch shared libraries to use relative RPATH + for lib in $out/lib/*.so*; do + if [ -f "$lib" ] && file "$lib" | grep -q ELF; then + echo "Patching RPATH for $lib" + # Set RPATH to $ORIGIN so libraries find other libraries in same directory + patchelf --set-rpath '$ORIGIN' "$lib" 2>/dev/null || true + # Shrink RPATH to remove any unused paths + patchelf --shrink-rpath "$lib" 2>/dev/null || true + fi + done + '' + + lib.optionalString stdenv.isDarwin '' + # On macOS, patch binaries to use relative library paths + # This makes the bundle portable across macOS systems + for bin in $out/bin/.*-wrapped; do + if [ -f "$bin" ] && file "$bin" | grep -q "Mach-O"; then + # Get all dylib dependencies from Nix store + otool -L "$bin" | grep /nix/store | awk '{print $1}' | while read dep; do + libname=$(basename "$dep") + # Check if we have this library in our lib directory + if [ -f "$out/lib/$libname" ]; then + echo "Patching $bin: $dep -> @rpath/$libname" + install_name_tool -change "$dep" "@rpath/$libname" "$bin" 2>/dev/null || true + fi + done + # Add @rpath to look in @executable_path/../lib + install_name_tool -add_rpath "@executable_path/../lib" "$bin" 2>/dev/null || true + fi + done + + # Patch dylibs to use @rpath for their dependencies + for lib in $out/lib/*.dylib*; do + if [ -f "$lib" ] && file "$lib" | grep -q "Mach-O"; then + # First, fix the library's own ID to use @rpath + libname=$(basename "$lib") + install_name_tool -id "@rpath/$libname" "$lib" 2>/dev/null || true + + # Add @rpath to the library itself so it can find other libraries + install_name_tool -add_rpath "@loader_path" "$lib" 2>/dev/null || true + + # Then fix references to other libraries + otool -L "$lib" | grep /nix/store | awk '{print $1}' | while read dep; do + deplibname=$(basename "$dep") + if [ -f "$out/lib/$deplibname" ]; then + echo "Patching $lib: $dep -> @rpath/$deplibname" + install_name_tool -change "$dep" "@rpath/$deplibname" "$lib" 2>/dev/null || true + fi + done + fi + done + ''; + + meta = { + description = "Supabae Edge Runtime for the Supabase CLI"; + license = lib.licenses.mit; + platforms = lib.platforms.unix; + maintainers = [ ]; + }; +} From f56495524dc211a8696aa7fee7b117b887229dac Mon Sep 17 00:00:00 2001 From: Kalleby Santos Date: Fri, 17 Apr 2026 18:06:47 +0100 Subject: [PATCH 2/3] refactor: cross-platform nix build --- flake.lock | 39 ++++++++++++++++++++-- flake.nix | 30 ++++++++++++----- nix/edge-runtime.nix | 78 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 122 insertions(+), 25 deletions(-) diff --git a/flake.lock b/flake.lock index 186b012c..697ed672 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,22 @@ { "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1775087534, + "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -20,11 +37,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1776361032, - "narHash": "sha256-Sg6Y1N7DwlHsk0Sq5HialITmRNvtZud+Ew9epPMxdNY=", + "lastModified": 1776432626, + "narHash": "sha256-9wlByeC3TeBR9zuf/8Y8hszL8pwVTQoGLFoRGBwZ99c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3ffdb960eea94b6eeef63eac8df173464aa3f145", + "rev": "21d424e294d026c5521783f7e36b50a4252482af", "type": "github" }, "original": { @@ -33,8 +50,24 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1774748309, + "narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "333c4e0545a6da976206c74db8773a1645b5870a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, "root": { "inputs": { + "flake-parts": "flake-parts", "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } diff --git a/flake.nix b/flake.nix index de94b08f..154fb7ef 100644 --- a/flake.nix +++ b/flake.nix @@ -4,13 +4,27 @@ nixpkgs.url = "github:NixOS/nixpkgs"; flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - in { - packages.edge-runtime = pkgs.callPackage ./nix/edge-runtime.nix { }; - defaultPackage = self.packages.${system}.edge-runtime; - }); + outputs = inputs @ { + self, + nixpkgs, + flake-utils, + flake-parts + }: flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "aarch64-darwin" + "aarch64-linux" + # TODO: Missing "x86_64-darwin" supabase/rusty_v8 + #"x86_64-darwin" + "x86_64-linux" + ]; + + perSystem = { system, pkgs, inputs', ... }: + rec { + packages = { + edge-runtime = pkgs.callPackage ./nix/edge-runtime.nix { }; + default = packages.edge-runtime; + }; + }; + }; } diff --git a/nix/edge-runtime.nix b/nix/edge-runtime.nix index fa490c9d..08f0fc1a 100644 --- a/nix/edge-runtime.nix +++ b/nix/edge-runtime.nix @@ -9,12 +9,71 @@ curl, fetchurl, cmake, + openssl, + zstd, }: let + system = stdenv.hostPlatform.system; + + v8Artifacts = { + "aarch64-darwin" = { + archive = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/librusty_v8_release_aarch64-apple-darwin.a.gz"; + sha256 = "sha256-VYWg+9WekcHBJWEq49eAAVpc6g/PPaoZDm/j2DKNQLY="; + }; + binding = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_aarch64-apple-darwin.rs"; + sha256 = "sha256-ytcUCd4V1MQkinakmT3rJsdow1RLVWrGqtMjava4BaU="; + }; + }; + + # TODO: Missing "x86_64-darwin" supabase/rusty_v8 + #"x86_64-darwin" = { + # archive = { + # url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_x86_64-apple-darwin.rs"; + # sha256 = "sha256-VYWg+9WekcHBJWEq49eAAVpc6g/PPaoZDm/j2DKNQLY="; + # }; + # binding = { + # url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_x86_64-apple-darwin.rs"; + # sha256 = lib.fakeHash; + # }; + #}; + + "aarch64-linux" = { + archive = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/librusty_v8_release_aarch64-unknown-linux-gnu.a.gz"; + sha256 = "sha256-8YupKkWyFn8oZ+RbEzcigdgwvIRjzE5GW7OSnmkIYHU="; + }; + binding = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_aarch64-unknown-linux-gnu.rs"; + sha256 = "sha256-sq8JII71BvnI43jNMm5yCj8WgGQ1K9n7AcOCJsfklRQ="; + }; + }; + "x86_64-linux" = { + archive = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7-patch.1/librusty_v8_release_x86_64-unknown-linux-gnu.a.gz"; + sha256 = "sha256-4tF7bHXad7K1ADwv3r718HUawEixSEOR5fNoBYJkFsA="; + }; + binding = { + url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_x86_64-unknown-linux-gnu.rs"; + sha256 = "sha256-sq8JII71BvnI43jNMm5yCj8WgGQ1K9n7AcOCJsfklRQ="; + }; + }; + }; + + v8 = v8Artifacts.${system} or (throw "Unsupported system: ${system}"); + v8Archive = fetchurl v8.archive; + v8Binding = fetchurl v8.binding; + build_step = rustPlatform.buildRustPackage (finalAttrs: { pname = "edge_runtime_build"; version = "v1.73.3"; src = ../.; + nativeBuildInputs = [ pkg-config curl cmake ]; + buildInputs = [ openblas onnxruntime openssl zstd ]; + propagatedBuildInputs = [ onnxruntime ]; + doCheck = false; + cargoLock = { lockFile = ../Cargo.lock; outputHashes = { @@ -25,21 +84,11 @@ let }; RUSTY_V8_MIRROR="null"; - RUST_BACKTRACE=1; - RUSTY_V8_SRC_BINDING_PATH = fetchurl { - url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/src_binding_release_aarch64-apple-darwin.rs"; - sha256 = "sha256-ytcUCd4V1MQkinakmT3rJsdow1RLVWrGqtMjava4BaU="; - }; - RUSTY_V8_ARCHIVE= fetchurl { - url = "https://github.com/supabase/rusty_v8/releases/download/v130.0.7/librusty_v8_release_aarch64-apple-darwin.a.gz"; - sha256 = "sha256-VYWg+9WekcHBJWEq49eAAVpc6g/PPaoZDm/j2DKNQLY="; - }; - DYLD_LIBRARY_PATH = "${onnxruntime}/lib"; + RUST_BACKTRACE="full"; - nativeBuildInputs = [ pkg-config curl cmake ]; - buildInputs = [ openblas onnxruntime ]; - propagatedBuildInputs = [ onnxruntime ]; - doCheck = false; + RUSTY_V8_ARCHIVE = v8Archive; + RUSTY_V8_SRC_BINDING_PATH = v8Binding; + DYLD_LIBRARY_PATH = "${onnxruntime}/lib"; }); in stdenv.mkDerivation { @@ -234,6 +283,7 @@ WRAPPER_EOF meta = { description = "Supabae Edge Runtime for the Supabase CLI"; + license = lib.licenses.mit; platforms = lib.platforms.unix; maintainers = [ ]; From f529e232990f51fd7d4440b7aafbf421617d4a2a Mon Sep 17 00:00:00 2001 From: Kalleby Santos Date: Mon, 20 Apr 2026 17:24:55 +0100 Subject: [PATCH 3/3] stamp: creating 'release-native' workflow --- .github/workflows/release-native.yml | 80 ++++++++++++++++++++++++++++ nix/edge-runtime.nix | 1 + 2 files changed, 81 insertions(+) create mode 100644 .github/workflows/release-native.yml diff --git a/.github/workflows/release-native.yml b/.github/workflows/release-native.yml new file mode 100644 index 00000000..c364aaf8 --- /dev/null +++ b/.github/workflows/release-native.yml @@ -0,0 +1,80 @@ +name: Release Native + +on: + push: + tags: + - "v*" + workflow_dispatch: + +permissions: + contents: write + +jobs: + build: + name: Build (${{ matrix.target }}) + strategy: + matrix: + include: + - runner: macos-14 + target: aarch64-darwin + - runner: ubuntu-24.04 + target: x86_64-linux + - runner: ubuntu-24.04-arm + target: aarch64-linux + runs-on: ${{ matrix.runner }} + + steps: + - uses: actions/checkout@v4 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@v13 + + - name: Restore Nix store cache + uses: actions/cache@v4 + with: + path: /nix/store + key: edge-runtime-${{ matrix.target }}-${{ hashFiles('flake.lock') }} + restore-keys: edge-runtime-${{ matrix.target }}- + + - name: Build + run: | + nix build --extra-experimental-features "nix-command flakes" \ + --system ${{ matrix.target }} + - name: Package + run: | + TAR="edge-runtime-${{ github.ref_name }}-${{ matrix.target }}.tar.gz" + tar czf "$TAR" \ + --dereference \ + -C "$(readlink -f ./result)" \ + . + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: edge-runtime-${{ matrix.target }} + path: edge-runtime-${{ github.ref_name }}-${{ matrix.target }}.tar.gz + retention-days: 1 + + release: + name: Create Release + needs: build + runs-on: ubuntu-latest + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: List files (debug) + run: ls -R artifacts + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + draft: false + prerelease: false + files: artifacts/**/* diff --git a/nix/edge-runtime.nix b/nix/edge-runtime.nix index 08f0fc1a..86fb1442 100644 --- a/nix/edge-runtime.nix +++ b/nix/edge-runtime.nix @@ -85,6 +85,7 @@ let RUSTY_V8_MIRROR="null"; RUST_BACKTRACE="full"; + RUSTFLAGS = "-C debuginfo=0"; RUSTY_V8_ARCHIVE = v8Archive; RUSTY_V8_SRC_BINDING_PATH = v8Binding;