Skip to content
Open
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
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1151,14 +1151,22 @@ yay -S omniroute-bin && systemctl --user enable --now omniroute.service
**🔧 Nix (Flake)**

```bash
# Using Nix flakes
# Install the package (requires flakes enabled)
nix profile install github:diegosouzapw/OmniRoute
# Or run ad-hoc without installing:
nix run github:diegosouzapw/OmniRoute -- --help

# Dev shell for hacking on the source:
nix develop
npm run dev

# Or using devbox
devbox run npm run dev
```

The package is tested on `x86_64-linux`. After each npm release, update it with
`node scripts/release/update-nix-package.mjs <version>` (needs npm, not Nix).

📖 [Docker Guide](docs/guides/DOCKER_GUIDE.md) — Compose profiles, Caddy HTTPS, Cloudflare tunnels.

**🦭 Podman**
Expand Down
1 change: 1 addition & 0 deletions changelog.d/features/13076-nix-package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **feat(nix):** Nix flake package for the published `omniroute` npm release — `buildNpmPackage` over a generated lockfile (`nix/package.json` + `nix/package-lock.json`), bins wrapped with the pinned Node.js, and `scripts/release/update-nix-package.mjs` to repoint it after each npm release ([#13076](https://github.com/cheaper-inference/OmniRoute/pull/13076)) — thanks @Ansh-Sonkusare
3 changes: 3 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
nodejs = pkgs.nodejs_24;
in
{
packages.default = pkgs.callPackage ./nix/omniroute.nix { nodejs = pkgs.nodejs_24; };
packages.omniroute = self.packages.${system}.default;

devShells.default = pkgs.mkShell {
buildInputs = [
nodejs
Expand Down
94 changes: 94 additions & 0 deletions nix/omniroute.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Builds the published npm tarball with `buildNpmPackage`.
#
# The tarball ships no lockfile, so `package-lock.json` here is generated from
# `package.json`, which is the published manifest minus `workspaces` and
# `devDependencies`. The app in the tarball is prebuilt, so dev tools are not
# needed. Their nested `overrides` also pin conflicting versions (undici,
# js-yaml), which makes npm ask the registry for metadata and fails offline.
# All `overrides` are kept, so the pinned versions still apply.
#
# `importNpmLock` fetches each dependency by the `integrity` in the lockfile,
# so there is no dependency hash to maintain. To update after an npm release,
# run `node scripts/release/update-nix-package.mjs [version]`. It rewrites
# `package.json`, `package-lock.json` and the source hash below, and needs npm
# but not Nix.
#
# Bin layout: `buildNpmPackage` links `$out/bin/omniroute` (and
# `omniroute-reset-password`) to the files under `lib/node_modules/omniroute`, and its
# shebang patching points them at the pinned `nodejs`. The CLI's own `serve` paths
# (bin/cli/commands/serve.mjs, `runDaemon` and `runWithoutRecovery`) and its runtime
# native-dependency installer (`npm`) still resolve `node`/`npm` through PATH, which a
# NixOS user does not have by default. So every installed bin is wrapped with
# `wrapProgram … --prefix PATH`, putting the same pinned `nodejs` (node + npm) first. The
# wrapper only prefixes PATH; the `lib/node_modules` layout is left untouched.
{
lib,
buildNpmPackage,
fetchurl,
importNpmLock,
makeWrapper,
nodejs,
}: let
package = lib.importJSON ./package.json;

# `importNpmLock` rewrites `dependencies` to store paths, and npm rejects an
# override that differs from its direct dependency (EOVERRIDE). Such overrides
# must already equal the dependency's range, so `$name` (npm's reference to
# the direct dependency) keeps the same meaning.
npmDepsPackage =
package
// {
overrides =
lib.mapAttrs (
name: value:
if builtins.isString value && package.dependencies ? ${name}
then "\$${name}"
else value
)
package.overrides;
};
in
buildNpmPackage {
pname = "omniroute";
inherit (package) version;
inherit nodejs;

src = fetchurl {
url = "https://registry.npmjs.org/omniroute/-/omniroute-${package.version}.tgz";
hash = "sha512-R+GUs3vDWpX36n+oOwjRSJN/7dGoXC3ehSV7mSz41nZM4mFhUo2+YepYzXMk5Hf6sIwCKRpGBaPMDVR8xbvwew==";
};
sourceRoot = "package";

postPatch = ''
cp ${./package.json} package.json
cp ${./package-lock.json} package-lock.json
'';

npmDeps = importNpmLock {
package = npmDepsPackage;
packageLock = lib.importJSON ./package-lock.json;
};
npmConfigHook = importNpmLock.npmConfigHook;

# The published tarball omits .npmrc, which sets this upstream.
npmFlags = ["--legacy-peer-deps"];
# Several install scripts download binaries, which the sandbox forbids.
npmRebuildFlags = ["--ignore-scripts"];
# `npm pack` would otherwise run the dev-only `prepare` script.
npmPackFlags = ["--ignore-scripts"];
dontNpmBuild = true;

nativeBuildInputs = [makeWrapper];
postInstall = ''
for bin in $out/bin/*; do
wrapProgram "$bin" --prefix PATH : ${lib.makeBinPath [nodejs]}
done
'';

meta = with lib; {
description = "Unified AI router with automatic provider fallback";
homepage = "https://github.com/diegosouzapw/OmniRoute";
license = licenses.mit;
mainProgram = "omniroute";
};
}
Loading
Loading