commit bd0b1c6ff4f37426ac81862e4238c67f72daed83 Author: Wyatt J. Miller Date: Fri Sep 4 14:16:55 2026 -0400 add: groundwork diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..7687c7f --- /dev/null +++ b/deno.json @@ -0,0 +1,8 @@ +{ + "tasks": { + "dev": "deno run --watch --allow-net main.ts" + }, + "imports": { + "@std/assert": "jsr:@std/assert@1" + } +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..94f8c32 --- /dev/null +++ b/flake.lock @@ -0,0 +1,42 @@ +{ + "nodes": { + "flake-schemas": { + "locked": { + "lastModified": 1780327564, + "narHash": "sha256-HiRPtA0spK+Dkgbhz/1zW9glXxNVB+L4Rj2VYmdawb8=", + "rev": "6cc9bd98891b1fc6bb2b8cb3277df8bc72799ca6", + "revCount": 149, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/DeterminateSystems/flake-schemas/0.5.0/019e83cf-9af3-78b1-ac5b-70e68ad1efe1/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/DeterminateSystems/flake-schemas/%2A.tar.gz" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1788404924, + "narHash": "sha256-lhEhY8X5EgkQ/eg6IFz4cc8jRuSYSvnxx1al7d1dvZ0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0968519e14f7aa7d3e9b389682bd74d2b51c8ce8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-schemas": "flake-schemas", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c00ab80 --- /dev/null +++ b/flake.nix @@ -0,0 +1,111 @@ +{ + description = "levin - storage conversion tool"; + inputs = { + flake-schemas.url = "https://flakehub.com/f/DeterminateSystems/flake-schemas/*.tar.gz"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + }; + + outputs = + { self + , flake-schemas + , nixpkgs + }: + let + supportedSystems = [ "x86_64-linux" "aarch64-darwin" "x86_64-darwin" "aarch64-linux" ]; + forEachSupportedSystem = f: + nixpkgs.lib.genAttrs supportedSystems (system: + f { + pkgs = import nixpkgs { inherit system; }; + }); + in + { + schemas = flake-schemas.schemas; + devShells = forEachSupportedSystem ({ pkgs }: { + default = pkgs.mkShell { + packages = with pkgs; [ + curl + git + jq + wget + nixpkgs-fmt + openssl + openssl.dev + patchelf + deno + pkg-config-unwrapped + ripgrep + ]; + + env = { + PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; + # ZELLIJ_CONFIG_FILE = "config.kdl"; + }; + }; + }); + + packages = forEachSupportedSystem ({ pkgs }: + let + levinVersion = "0.0.1"; + denoDeps = pkgs.stdenvNoCC.mkDerivation { + pname = "levin-deno-deps"; + version = levinVersion; + src = ./.; + nativeBuildInputs = [ pkgs.deno pkgs.cacert ]; + dontConfigure = true; + buildPhase = '' + runHook preBuild + export HOME="$TMPDIR" + export DENO_DIR="$TMPDIR/deno-dir" + deno cache --vendor=false --frozen --lock=deno.lock main.ts + deno compile \ + --vendor=false \ + --frozen \ + --lock=deno.lock \ + --output "$TMPDIR/levin-cache-primer" \ + main.ts + runHook postBuild + ''; + installPhase = '' + runHook preInstall + mkdir -p "$out" + cp -R "$DENO_DIR"/. "$out" + runHook postInstall + ''; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + outputHash = "sha256-ndPlYrPgqHE4iE08JnKWPxAZfjWGd0Ez76aY4R1eITs="; + }; + in + { + levin = pkgs.stdenvNoCC.mkDerivation { + pname = "levin"; + version = levinVersion; + src = ./.; + nativeBuildInputs = [ pkgs.deno ]; + dontConfigure = true; + dontFixup = true; + buildPhase = '' + runHook preBuild + export HOME="$TMPDIR" + export DENO_DIR="$TMPDIR/deno-dir" + cp -R ${denoDeps}/. "$DENO_DIR" + chmod -R u+w "$DENO_DIR" + deno compile \ + --vendor=false \ + --cached-only \ + --frozen \ + --lock=deno.lock \ + --allow-all \ + --output levin \ + main.ts + runHook postBuild + ''; + installPhase = '' + runHook preInstall + install -Dm755 levin "$out/bin/levin" + runHook postInstall + ''; + }; + }); + }; +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..3922f65 --- /dev/null +++ b/main.ts @@ -0,0 +1,28 @@ +const units = { + B: 1, + + kB: 1000 ** 1, + KiB: 1024 ** 1, + + MB: 1000 ** 2, + MiB: 1024 ** 2, + + GB: 1000 ** 3, + GiB: 1024 ** 3, + + TB: 1000 ** 4, + TiB: 1024 ** 4, + + PB: 1000 ** 5, + PiB: 1024 ** 5, +} as const; + +type Unit = keyof typeof units; + +function convert(value: number, from: Unit, to: Unit): number { + return value * units[from] / units[to]; +} + +if (import.meta.main) { + console.log(convert(1, "MiB", "kB")); +} diff --git a/main_test.ts b/main_test.ts new file mode 100644 index 0000000..9432a66 --- /dev/null +++ b/main_test.ts @@ -0,0 +1,16 @@ +import { assertEquals } from "@std/assert"; +import { handler } from "./main.ts"; + +Deno.test("returns html on /", async () => { + const res = handler(new Request("http://localhost/")); + assertEquals(res.headers.get("content-type"), "text/html"); + const body = await res.text(); + assertEquals(body.includes("Welcome to Deno"), true); +}); + +Deno.test("returns json on /api", async () => { + const res = handler(new Request("http://localhost/api")); + const data = await res.json(); + assertEquals(data.message, "Hello, world!"); + assertEquals(typeof data.time, "string"); +});