mirror of
https://github.com/kennethnym/freya
synced 2026-06-19 16:11:18 +01:00
Upgrade the React Native client through Expo SDK 56, align workspace React versions, switch Bun installs to the hoisted linker for Expo compatibility, and fix the Metro proxy to handle localhost/IPv6 loopback after the SDK upgrade.
283 lines
8.4 KiB
Nix
283 lines
8.4 KiB
Nix
{
|
|
description = "FREYA development shell";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
};
|
|
|
|
outputs =
|
|
{ nixpkgs, ... }:
|
|
let
|
|
systems = [
|
|
"x86_64-linux"
|
|
"aarch64-linux"
|
|
"x86_64-darwin"
|
|
"aarch64-darwin"
|
|
];
|
|
|
|
lib = nixpkgs.lib;
|
|
forEachSystem = lib.genAttrs systems;
|
|
pkgsFor = forEachSystem (system: import nixpkgs { inherit system; });
|
|
|
|
# App outputs are for long-running local tools and dev servers.
|
|
appScripts = {
|
|
expo = "expo";
|
|
drizzle-studio = "drizzle-studio";
|
|
freya-backend = "freya-backend";
|
|
admin-dashboard = "admin-dashboard";
|
|
agent-test-cli = "agent-test-cli";
|
|
};
|
|
|
|
# Check outputs are the CI-like validation commands run by `nix flake check`.
|
|
checkCommands = {
|
|
format-check = "bun run format:check";
|
|
lint = "bun run lint";
|
|
test = "bun run test";
|
|
};
|
|
|
|
# Dev-shell conveniences mirror the common app/check commands.
|
|
shellScripts = appScripts // {
|
|
freya-test = "test";
|
|
lint = "lint";
|
|
format-check = "format:check";
|
|
};
|
|
|
|
# node_modules is content-addressed. If bun.lock or package manifests
|
|
# change, Nix will report the new hash to put here.
|
|
nodeModulesHashes = {
|
|
x86_64-linux = "sha256-8uhlaQAFfCgGdUlrz8sqhtIkC/WfdasbTCi3p/NkU/w=";
|
|
};
|
|
checkSystems = lib.attrNames nodeModulesHashes;
|
|
|
|
# Dependency derivations only need the lockfile and workspace manifests,
|
|
# so source-only edits do not force Bun to reinstall.
|
|
dependencySource = lib.fileset.toSource {
|
|
root = ./.;
|
|
fileset = lib.fileset.fileFilter (
|
|
file: file.name == "bun.lock" || file.name == "package.json" || file.name == "bunfig.toml"
|
|
) ./.;
|
|
};
|
|
|
|
# Checks run against a clean source tree, even when using `path:.`.
|
|
# Without this filter, local node_modules can sneak into the Nix sandbox.
|
|
projectSource = builtins.path {
|
|
name = "freya-source";
|
|
path = ./.;
|
|
filter =
|
|
path: type:
|
|
let
|
|
name = builtins.baseNameOf path;
|
|
in
|
|
!(type == "directory" && (name == ".git" || name == "node_modules")) && name != "result";
|
|
};
|
|
|
|
mkBunScriptCommands =
|
|
pkgs: scripts:
|
|
let
|
|
mkBunScript =
|
|
name: script:
|
|
pkgs.writeShellApplication {
|
|
inherit name;
|
|
runtimeInputs = with pkgs; [
|
|
bun
|
|
git
|
|
];
|
|
text = ''
|
|
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
cd "$repo_root"
|
|
exec bun run ${lib.escapeShellArg script} "$@"
|
|
'';
|
|
};
|
|
in
|
|
lib.mapAttrs mkBunScript scripts;
|
|
mkBunApps =
|
|
commands:
|
|
lib.mapAttrs (name: command: {
|
|
type = "app";
|
|
program = "${command}/bin/${name}";
|
|
}) commands;
|
|
mkBunNodeModules =
|
|
system: pkgs:
|
|
pkgs.stdenvNoCC.mkDerivation {
|
|
pname = "freya-node-modules";
|
|
version = "1";
|
|
__structuredAttrs = true;
|
|
|
|
src = dependencySource;
|
|
nativeBuildInputs = with pkgs; [
|
|
bun
|
|
cacert
|
|
nodejs
|
|
];
|
|
|
|
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
|
GIT_SSL_CAINFO = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
|
|
|
outputHashAlgo = "sha256";
|
|
outputHashMode = "recursive";
|
|
outputHash = nodeModulesHashes.${system};
|
|
|
|
# `patchShebangs` embeds Nix store interpreters in package bins. The
|
|
# check derivations also depend on bun/node, so this dependency blob
|
|
# can safely drop those references after its hash is verified.
|
|
unsafeDiscardReferences.out = true;
|
|
|
|
dontConfigure = true;
|
|
# Workspace package links are completed inside each check's source tree,
|
|
# so they are intentionally dangling in this dependency-only output.
|
|
dontFixup = true;
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
export HOME="$TMPDIR/home"
|
|
mkdir -p "$HOME"
|
|
|
|
# Keep the real workspace manifest for `--frozen-lockfile`, but
|
|
# filter out frontend workspaces that do not participate in checks.
|
|
# `--force` matters in the Nix sandbox: without it, Bun can accept
|
|
# manifest-only cached packages and leave tool binaries missing.
|
|
bun install \
|
|
--force \
|
|
--frozen-lockfile \
|
|
--ignore-scripts \
|
|
--backend copyfile \
|
|
--filter freya \
|
|
--filter '@freya/*' \
|
|
--filter '@freya/backend' \
|
|
--no-progress
|
|
|
|
patchShebangs node_modules
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mkdir -p "$out"
|
|
|
|
# Keep the root install in the store; checks symlink this directly.
|
|
cp -a node_modules "$out/node_modules"
|
|
|
|
# Bun also creates per-workspace node_modules directories. These are
|
|
# mostly relative symlinks, so checks copy the symlink entries into
|
|
# their writable source tree instead of symlinking the directory.
|
|
find apps packages -mindepth 2 -maxdepth 2 -type d -name node_modules -print |
|
|
while IFS= read -r node_modules_dir; do
|
|
mkdir -p "$out/$(dirname "$node_modules_dir")"
|
|
cp -a "$node_modules_dir" "$out/$node_modules_dir"
|
|
done
|
|
|
|
runHook postInstall
|
|
'';
|
|
};
|
|
mkBunCheck =
|
|
pkgs: nodeModules: name: command:
|
|
pkgs.stdenvNoCC.mkDerivation {
|
|
pname = "freya-${name}";
|
|
version = "1";
|
|
|
|
src = projectSource;
|
|
nativeBuildInputs = with pkgs; [
|
|
bun
|
|
nodejs
|
|
];
|
|
|
|
dontConfigure = true;
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
export HOME="$TMPDIR/home"
|
|
mkdir -p "$HOME"
|
|
|
|
# Root dependencies are read-only and shared across checks.
|
|
ln -s "${nodeModules}/node_modules" node_modules
|
|
|
|
# Workspace node_modules contain relative symlinks back to packages/
|
|
# and apps/, so copy just those symlink entries into this source tree.
|
|
for node_modules_dir in "${nodeModules}"/apps/*/node_modules "${nodeModules}"/packages/*/node_modules; do
|
|
if [ -d "$node_modules_dir" ]; then
|
|
relative_path="''${node_modules_dir#"${nodeModules}/"}"
|
|
mkdir -p "$relative_path"
|
|
cp -a "$node_modules_dir/." "$relative_path/"
|
|
fi
|
|
done
|
|
|
|
${command}
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mkdir -p "$out"
|
|
touch "$out/${name}"
|
|
|
|
runHook postInstall
|
|
'';
|
|
};
|
|
in
|
|
{
|
|
apps = forEachSystem (
|
|
system:
|
|
let
|
|
pkgs = pkgsFor.${system};
|
|
in
|
|
mkBunApps (mkBunScriptCommands pkgs appScripts)
|
|
);
|
|
|
|
checks = lib.genAttrs checkSystems (
|
|
system:
|
|
let
|
|
pkgs = pkgsFor.${system};
|
|
nodeModules = mkBunNodeModules system pkgs;
|
|
in
|
|
lib.mapAttrs (mkBunCheck pkgs nodeModules) checkCommands
|
|
);
|
|
|
|
devShells = forEachSystem (
|
|
system:
|
|
let
|
|
pkgs = pkgsFor.${system};
|
|
bunScriptCommands = lib.attrValues (mkBunScriptCommands pkgs shellScripts);
|
|
commonPackages = with pkgs; [
|
|
bun
|
|
eas-cli
|
|
git
|
|
gh
|
|
gnumake
|
|
nixfmt
|
|
nodejs
|
|
openssl
|
|
pkg-config
|
|
postgresql
|
|
python3
|
|
watchman
|
|
];
|
|
linuxPackages = with pkgs; [
|
|
gcc
|
|
inotify-tools
|
|
tailscale
|
|
];
|
|
in
|
|
{
|
|
default = pkgs.mkShell {
|
|
packages =
|
|
commonPackages ++ bunScriptCommands ++ pkgs.lib.optionals pkgs.stdenv.isLinux linuxPackages;
|
|
|
|
SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
|
|
|
shellHook = ''
|
|
export PATH="$PWD/node_modules/.bin:$PATH"
|
|
'';
|
|
};
|
|
}
|
|
);
|
|
|
|
formatter = forEachSystem (system: pkgsFor.${system}.nixfmt);
|
|
};
|
|
}
|