From 119e44165a2a1581eef12390df9936511276e03c Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Tue, 22 Feb 2022 03:01:39 +0000
Subject: [PATCH] Add initial client-side system

Looks like esbuild is shaping up to be just the thing we need, and wow
is it fast!

Still ned to figure out how to get it to not mangle the index.html
filename, but still!
---
 .gitignore                          |   2 +-
 README.md                           |   8 +
 package-lock.json                   | 515 ++++++++++++++++++++++++++++
 package.json                        |   4 +
 src/static/app.css                  |   1 +
 src/static/app.mjs                  |  10 +
 src/static/esbuild.mjs              |  34 ++
 src/static/index.html               |  24 ++
 src/static/js/SystemQueryClient.mjs |  11 +
 src/static/js/routes/route_main.mjs |   5 +
 src/static/js/routes_client.mjs     |  11 +
 11 files changed, 624 insertions(+), 1 deletion(-)
 create mode 100644 src/static/app.css
 create mode 100644 src/static/app.mjs
 create mode 100755 src/static/esbuild.mjs
 create mode 100644 src/static/index.html
 create mode 100644 src/static/js/SystemQueryClient.mjs
 create mode 100644 src/static/js/routes/route_main.mjs
 create mode 100644 src/static/js/routes_client.mjs

diff --git a/.gitignore b/.gitignore
index 67699b9..b3e4aac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
 /target
 config/
-
+static-dist/
 
 # Created by https://www.toptal.com/developers/gitignore/api/rust,git
 # Edit at https://www.toptal.com/developers/gitignore?templates=rust,git
diff --git a/README.md b/README.md
index 8e5881d..d345ea8 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,14 @@
 
 
 
+## FAQ
+
+### Q: I see a scary native binary build system in the development dependencies!
+A: You're probably referring to [esbuild](https://esbuild.github.io/). If you install systemquery from npm, the build steps for the client-side javascript will already have been completed, thereby negating the need to install a native binary.
+
+The advantage of using a build system for the client-side browser resources is significantly improved performance. With this approach, we get the benefit of a build system without needing to install a native binary on target machines which might be incompatible with the host machine's CPU architecture.
+
+
 ## Useful Links
 
  - [jpake](https://www.npmjs.com/package/jpake) - ~~in case our STARTTLS-based idea doesn't work~~ it didn't work :-/
diff --git a/package-lock.json b/package-lock.json
index d6b0898..6d8edc3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
       "dependencies": {
         "@ltd/j-toml": "^1.29.0",
         "applause-cli": "^1.8.0",
+        "fork-awesome": "^1.2.0",
         "jpake": "^1.0.1",
         "nexline": "^1.2.2",
         "p-queue": "^7.2.0",
@@ -19,6 +20,9 @@
         "powahroot": "^1.1.1",
         "systeminformation": "^5.11.2",
         "tweetnacl": "^1.0.3"
+      },
+      "devDependencies": {
+        "esbuild": "^0.14.23"
       }
     },
     "node_modules/@ltd/j-toml": {
@@ -62,6 +66,344 @@
       "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
       "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
     },
+    "node_modules/esbuild": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.23.tgz",
+      "integrity": "sha512-XjnIcZ9KB6lfonCa+jRguXyRYcldmkyZ99ieDksqW/C8bnyEX299yA4QH2XcgijCgaddEZePPTgvx/2imsq7Ig==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "esbuild-android-arm64": "0.14.23",
+        "esbuild-darwin-64": "0.14.23",
+        "esbuild-darwin-arm64": "0.14.23",
+        "esbuild-freebsd-64": "0.14.23",
+        "esbuild-freebsd-arm64": "0.14.23",
+        "esbuild-linux-32": "0.14.23",
+        "esbuild-linux-64": "0.14.23",
+        "esbuild-linux-arm": "0.14.23",
+        "esbuild-linux-arm64": "0.14.23",
+        "esbuild-linux-mips64le": "0.14.23",
+        "esbuild-linux-ppc64le": "0.14.23",
+        "esbuild-linux-riscv64": "0.14.23",
+        "esbuild-linux-s390x": "0.14.23",
+        "esbuild-netbsd-64": "0.14.23",
+        "esbuild-openbsd-64": "0.14.23",
+        "esbuild-sunos-64": "0.14.23",
+        "esbuild-windows-32": "0.14.23",
+        "esbuild-windows-64": "0.14.23",
+        "esbuild-windows-arm64": "0.14.23"
+      }
+    },
+    "node_modules/esbuild-android-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.23.tgz",
+      "integrity": "sha512-k9sXem++mINrZty1v4FVt6nC5BQCFG4K2geCIUUqHNlTdFnuvcqsY7prcKZLFhqVC1rbcJAr9VSUGFL/vD4vsw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-darwin-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.23.tgz",
+      "integrity": "sha512-lB0XRbtOYYL1tLcYw8BoBaYsFYiR48RPrA0KfA/7RFTr4MV7Bwy/J4+7nLsVnv9FGuQummM3uJ93J3ptaTqFug==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-darwin-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.23.tgz",
+      "integrity": "sha512-yat73Z/uJ5tRcfRiI4CCTv0FSnwErm3BJQeZAh+1tIP0TUNh6o+mXg338Zl5EKChD+YGp6PN+Dbhs7qa34RxSw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-freebsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.23.tgz",
+      "integrity": "sha512-/1xiTjoLuQ+LlbfjJdKkX45qK/M7ARrbLmyf7x3JhyQGMjcxRYVR6Dw81uH3qlMHwT4cfLW4aEVBhP1aNV7VsA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-freebsd-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.23.tgz",
+      "integrity": "sha512-uyPqBU/Zcp6yEAZS4LKj5jEE0q2s4HmlMBIPzbW6cTunZ8cyvjG6YWpIZXb1KK3KTJDe62ltCrk3VzmWHp+iLg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-32": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.23.tgz",
+      "integrity": "sha512-37R/WMkQyUfNhbH7aJrr1uCjDVdnPeTHGeDhZPUNhfoHV0lQuZNCKuNnDvlH/u/nwIYZNdVvz1Igv5rY/zfrzQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.23.tgz",
+      "integrity": "sha512-H0gztDP60qqr8zoFhAO64waoN5yBXkmYCElFklpd6LPoobtNGNnDe99xOQm28+fuD75YJ7GKHzp/MLCLhw2+vQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-arm": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.23.tgz",
+      "integrity": "sha512-x64CEUxi8+EzOAIpCUeuni0bZfzPw/65r8tC5cy5zOq9dY7ysOi5EVQHnzaxS+1NmV+/RVRpmrzGw1QgY2Xpmw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.23.tgz",
+      "integrity": "sha512-c4MLOIByNHR55n3KoYf9hYDfBRghMjOiHLaoYLhkQkIabb452RWi+HsNgB41sUpSlOAqfpqKPFNg7VrxL3UX9g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-mips64le": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.23.tgz",
+      "integrity": "sha512-kHKyKRIAedYhKug2EJpyJxOUj3VYuamOVA1pY7EimoFPzaF3NeY7e4cFBAISC/Av0/tiV0xlFCt9q0HJ68IBIw==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-ppc64le": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.23.tgz",
+      "integrity": "sha512-7ilAiJEPuJJnJp/LiDO0oJm5ygbBPzhchJJh9HsHZzeqO+3PUzItXi+8PuicY08r0AaaOe25LA7sGJ0MzbfBag==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-riscv64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.23.tgz",
+      "integrity": "sha512-fbL3ggK2wY0D8I5raPIMPhpCvODFE+Bhb5QGtNP3r5aUsRR6TQV+ZBXIaw84iyvKC8vlXiA4fWLGhghAd/h/Zg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-linux-s390x": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.23.tgz",
+      "integrity": "sha512-GHMDCyfy7+FaNSO8RJ8KCFsnax8fLUsOrj9q5Gi2JmZMY0Zhp75keb5abTFCq2/Oy6KVcT0Dcbyo/bFb4rIFJA==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-netbsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.23.tgz",
+      "integrity": "sha512-ovk2EX+3rrO1M2lowJfgMb/JPN1VwVYrx0QPUyudxkxLYrWeBxDKQvc6ffO+kB4QlDyTfdtAURrVzu3JeNdA2g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-openbsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.23.tgz",
+      "integrity": "sha512-uYYNqbVR+i7k8ojP/oIROAHO9lATLN7H2QeXKt2H310Fc8FJj4y3Wce6hx0VgnJ4k1JDrgbbiXM8rbEgQyg8KA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-sunos-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.23.tgz",
+      "integrity": "sha512-hAzeBeET0+SbScknPzS2LBY6FVDpgE+CsHSpe6CEoR51PApdn2IB0SyJX7vGelXzlyrnorM4CAsRyb9Qev4h9g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-32": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.23.tgz",
+      "integrity": "sha512-Kttmi3JnohdaREbk6o9e25kieJR379TsEWF0l39PQVHXq3FR6sFKtVPgY8wk055o6IB+rllrzLnbqOw/UV60EA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.23.tgz",
+      "integrity": "sha512-JtIT0t8ymkpl6YlmOl6zoSWL5cnCgyLaBdf/SiU/Eg3C13r0NbHZWNT/RDEMKK91Y6t79kTs3vyRcNZbfu5a8g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/esbuild-windows-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.23.tgz",
+      "integrity": "sha512-cTFaQqT2+ik9e4hePvYtRZQ3pqOvKDVNarzql0VFIzhc0tru/ZgdLoXd6epLiKT+SzoSce6V9YJ+nn6RCn6SHw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/event-emitter-es6": {
       "version": "1.1.5",
       "resolved": "https://registry.npmjs.org/event-emitter-es6/-/event-emitter-es6-1.1.5.tgz",
@@ -72,6 +414,14 @@
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
       "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
     },
+    "node_modules/fork-awesome": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fork-awesome/-/fork-awesome-1.2.0.tgz",
+      "integrity": "sha512-MNwTBnnudMIweHfDtTY8TeR5fxIAZ2w9o8ITn5XDySqdxa4k5AH8IuAMa89RVxDxgPNlosZxqkFKN5UmHXuYSw==",
+      "engines": {
+        "node": ">=0.10.3"
+      }
+    },
     "node_modules/fs-extra": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -304,6 +654,166 @@
       "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
       "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
     },
+    "esbuild": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.23.tgz",
+      "integrity": "sha512-XjnIcZ9KB6lfonCa+jRguXyRYcldmkyZ99ieDksqW/C8bnyEX299yA4QH2XcgijCgaddEZePPTgvx/2imsq7Ig==",
+      "dev": true,
+      "requires": {
+        "esbuild-android-arm64": "0.14.23",
+        "esbuild-darwin-64": "0.14.23",
+        "esbuild-darwin-arm64": "0.14.23",
+        "esbuild-freebsd-64": "0.14.23",
+        "esbuild-freebsd-arm64": "0.14.23",
+        "esbuild-linux-32": "0.14.23",
+        "esbuild-linux-64": "0.14.23",
+        "esbuild-linux-arm": "0.14.23",
+        "esbuild-linux-arm64": "0.14.23",
+        "esbuild-linux-mips64le": "0.14.23",
+        "esbuild-linux-ppc64le": "0.14.23",
+        "esbuild-linux-riscv64": "0.14.23",
+        "esbuild-linux-s390x": "0.14.23",
+        "esbuild-netbsd-64": "0.14.23",
+        "esbuild-openbsd-64": "0.14.23",
+        "esbuild-sunos-64": "0.14.23",
+        "esbuild-windows-32": "0.14.23",
+        "esbuild-windows-64": "0.14.23",
+        "esbuild-windows-arm64": "0.14.23"
+      }
+    },
+    "esbuild-android-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.23.tgz",
+      "integrity": "sha512-k9sXem++mINrZty1v4FVt6nC5BQCFG4K2geCIUUqHNlTdFnuvcqsY7prcKZLFhqVC1rbcJAr9VSUGFL/vD4vsw==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-darwin-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.23.tgz",
+      "integrity": "sha512-lB0XRbtOYYL1tLcYw8BoBaYsFYiR48RPrA0KfA/7RFTr4MV7Bwy/J4+7nLsVnv9FGuQummM3uJ93J3ptaTqFug==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-darwin-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.23.tgz",
+      "integrity": "sha512-yat73Z/uJ5tRcfRiI4CCTv0FSnwErm3BJQeZAh+1tIP0TUNh6o+mXg338Zl5EKChD+YGp6PN+Dbhs7qa34RxSw==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-freebsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.23.tgz",
+      "integrity": "sha512-/1xiTjoLuQ+LlbfjJdKkX45qK/M7ARrbLmyf7x3JhyQGMjcxRYVR6Dw81uH3qlMHwT4cfLW4aEVBhP1aNV7VsA==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-freebsd-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.23.tgz",
+      "integrity": "sha512-uyPqBU/Zcp6yEAZS4LKj5jEE0q2s4HmlMBIPzbW6cTunZ8cyvjG6YWpIZXb1KK3KTJDe62ltCrk3VzmWHp+iLg==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-32": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.23.tgz",
+      "integrity": "sha512-37R/WMkQyUfNhbH7aJrr1uCjDVdnPeTHGeDhZPUNhfoHV0lQuZNCKuNnDvlH/u/nwIYZNdVvz1Igv5rY/zfrzQ==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.23.tgz",
+      "integrity": "sha512-H0gztDP60qqr8zoFhAO64waoN5yBXkmYCElFklpd6LPoobtNGNnDe99xOQm28+fuD75YJ7GKHzp/MLCLhw2+vQ==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-arm": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.23.tgz",
+      "integrity": "sha512-x64CEUxi8+EzOAIpCUeuni0bZfzPw/65r8tC5cy5zOq9dY7ysOi5EVQHnzaxS+1NmV+/RVRpmrzGw1QgY2Xpmw==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.23.tgz",
+      "integrity": "sha512-c4MLOIByNHR55n3KoYf9hYDfBRghMjOiHLaoYLhkQkIabb452RWi+HsNgB41sUpSlOAqfpqKPFNg7VrxL3UX9g==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-mips64le": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.23.tgz",
+      "integrity": "sha512-kHKyKRIAedYhKug2EJpyJxOUj3VYuamOVA1pY7EimoFPzaF3NeY7e4cFBAISC/Av0/tiV0xlFCt9q0HJ68IBIw==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-ppc64le": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.23.tgz",
+      "integrity": "sha512-7ilAiJEPuJJnJp/LiDO0oJm5ygbBPzhchJJh9HsHZzeqO+3PUzItXi+8PuicY08r0AaaOe25LA7sGJ0MzbfBag==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-riscv64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.23.tgz",
+      "integrity": "sha512-fbL3ggK2wY0D8I5raPIMPhpCvODFE+Bhb5QGtNP3r5aUsRR6TQV+ZBXIaw84iyvKC8vlXiA4fWLGhghAd/h/Zg==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-linux-s390x": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.23.tgz",
+      "integrity": "sha512-GHMDCyfy7+FaNSO8RJ8KCFsnax8fLUsOrj9q5Gi2JmZMY0Zhp75keb5abTFCq2/Oy6KVcT0Dcbyo/bFb4rIFJA==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-netbsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.23.tgz",
+      "integrity": "sha512-ovk2EX+3rrO1M2lowJfgMb/JPN1VwVYrx0QPUyudxkxLYrWeBxDKQvc6ffO+kB4QlDyTfdtAURrVzu3JeNdA2g==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-openbsd-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.23.tgz",
+      "integrity": "sha512-uYYNqbVR+i7k8ojP/oIROAHO9lATLN7H2QeXKt2H310Fc8FJj4y3Wce6hx0VgnJ4k1JDrgbbiXM8rbEgQyg8KA==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-sunos-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.23.tgz",
+      "integrity": "sha512-hAzeBeET0+SbScknPzS2LBY6FVDpgE+CsHSpe6CEoR51PApdn2IB0SyJX7vGelXzlyrnorM4CAsRyb9Qev4h9g==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-windows-32": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.23.tgz",
+      "integrity": "sha512-Kttmi3JnohdaREbk6o9e25kieJR379TsEWF0l39PQVHXq3FR6sFKtVPgY8wk055o6IB+rllrzLnbqOw/UV60EA==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-windows-64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.23.tgz",
+      "integrity": "sha512-JtIT0t8ymkpl6YlmOl6zoSWL5cnCgyLaBdf/SiU/Eg3C13r0NbHZWNT/RDEMKK91Y6t79kTs3vyRcNZbfu5a8g==",
+      "dev": true,
+      "optional": true
+    },
+    "esbuild-windows-arm64": {
+      "version": "0.14.23",
+      "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.23.tgz",
+      "integrity": "sha512-cTFaQqT2+ik9e4hePvYtRZQ3pqOvKDVNarzql0VFIzhc0tru/ZgdLoXd6epLiKT+SzoSce6V9YJ+nn6RCn6SHw==",
+      "dev": true,
+      "optional": true
+    },
     "event-emitter-es6": {
       "version": "1.1.5",
       "resolved": "https://registry.npmjs.org/event-emitter-es6/-/event-emitter-es6-1.1.5.tgz",
@@ -314,6 +824,11 @@
       "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
       "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
     },
+    "fork-awesome": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fork-awesome/-/fork-awesome-1.2.0.tgz",
+      "integrity": "sha512-MNwTBnnudMIweHfDtTY8TeR5fxIAZ2w9o8ITn5XDySqdxa4k5AH8IuAMa89RVxDxgPNlosZxqkFKN5UmHXuYSw=="
+    },
     "fs-extra": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
diff --git a/package.json b/package.json
index 1e29efa..6ee63bd 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
   "dependencies": {
     "@ltd/j-toml": "^1.29.0",
     "applause-cli": "^1.8.0",
+    "fork-awesome": "^1.2.0",
     "jpake": "^1.0.1",
     "nexline": "^1.2.2",
     "p-queue": "^7.2.0",
@@ -27,5 +28,8 @@
     "powahroot": "^1.1.1",
     "systeminformation": "^5.11.2",
     "tweetnacl": "^1.0.3"
+  },
+  "devDependencies": {
+    "esbuild": "^0.14.23"
   }
 }
diff --git a/src/static/app.css b/src/static/app.css
new file mode 100644
index 0000000..9de6160
--- /dev/null
+++ b/src/static/app.css
@@ -0,0 +1 @@
+@import "fork-awesome/css/fork-awesome.min.css";
diff --git a/src/static/app.mjs b/src/static/app.mjs
new file mode 100644
index 0000000..d17e279
--- /dev/null
+++ b/src/static/app.mjs
@@ -0,0 +1,10 @@
+import __INDEX__ from "./index.html";
+
+import make_router from './js/routes_client.mjs';
+
+window.addEventListener("load", (_event) => {
+	globalThis[Symbol("__INDEX__")] = __INDEX__;
+	globalThis.sysquery_router = make_router();
+	
+	globalThis.sysquery_router.navigate_current_hash();
+});
diff --git a/src/static/esbuild.mjs b/src/static/esbuild.mjs
new file mode 100755
index 0000000..912e372
--- /dev/null
+++ b/src/static/esbuild.mjs
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+"use strict";
+
+import path from 'path';
+
+import esbuild from 'esbuild';
+
+const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
+
+(async () => {
+    "use strict";
+    
+	const result = await esbuild.build({
+		entryPoints: [
+			"./app.mjs",
+			"./app.css"
+		].map(filepath => path.resolve(__dirname, filepath)),
+		outdir: path.resolve(__dirname, "../static-dist"),
+		bundle: true,
+		minify: true,
+		sourcemap: true,
+		loader: {
+			".html": "file",
+			".svg": "file",
+			".woff2": "file",
+			".woff": "file",
+			".eot": "file",
+			".ttf": "file"
+		}
+	});
+	console.log(result);
+	
+	// console.log(await esbuild.analyzeMetafile(result.metafile));
+})();
diff --git a/src/static/index.html b/src/static/index.html
new file mode 100644
index 0000000..37a6d9d
--- /dev/null
+++ b/src/static/index.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset='utf-8' />
+		<title>systemquery</title>
+	</head>
+	<body>
+		<header>
+			<h1>systemquery</h1>
+			<p>Version <span class="systemquery-version"></span></p>
+		</header>
+		
+		<nav>
+			<ul class="nav-items">
+				
+				<li><a href="#settings">Settings</a></li>
+			</ul>
+		</nav>
+		
+		<!---------------->
+		<link rel="stylesheet" href="/static/app.css" />
+		<script src="/static/app.js" charset="utf-8"></script>
+	</body>
+</html>
diff --git a/src/static/js/SystemQueryClient.mjs b/src/static/js/SystemQueryClient.mjs
new file mode 100644
index 0000000..01cc437
--- /dev/null
+++ b/src/static/js/SystemQueryClient.mjs
@@ -0,0 +1,11 @@
+"use strict";
+
+class SystemQueryClient {
+	constructor() {
+		
+	}
+	
+	// TODO: Implement fetch-based client API for the UI logic to use here
+}
+
+export default SystemQueryClient;
diff --git a/src/static/js/routes/route_main.mjs b/src/static/js/routes/route_main.mjs
new file mode 100644
index 0000000..f6537dd
--- /dev/null
+++ b/src/static/js/routes/route_main.mjs
@@ -0,0 +1,5 @@
+"use strict";
+
+export default function route_main() {
+	console.log(`The main route`);
+}
diff --git a/src/static/js/routes_client.mjs b/src/static/js/routes_client.mjs
new file mode 100644
index 0000000..98e69fd
--- /dev/null
+++ b/src/static/js/routes_client.mjs
@@ -0,0 +1,11 @@
+import ClientRouter from 'powahroot/Client.mjs';
+
+import route_main from './routes/route_main.mjs';
+
+export default function make_routes() {
+	const router = new ClientRouter();
+	
+	router.add_page("/", route_main);
+	
+	return router;
+}
