242 lines
6.6 KiB
Nix
242 lines
6.6 KiB
Nix
# NixOS module for building and serving the Vue 3 webapp
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
cfg = config.services.webapp;
|
|
|
|
# Build the Vue 3 webapp using buildNpmPackage
|
|
webapp = pkgs.buildNpmPackage {
|
|
pname = "aio-webapp";
|
|
version = "1.0.0";
|
|
|
|
# Fetch source from git repository
|
|
src = builtins.fetchGit {
|
|
url = cfg.gitUrl;
|
|
ref = cfg.gitRef;
|
|
};
|
|
|
|
# SHA256 hash of npm dependencies
|
|
# Run `nix-prefetch-npm-deps package-lock.json` to get this hash
|
|
# Or use lib.fakeHash initially and let the build tell you the correct hash
|
|
npmDepsHash = cfg.npmDepsHash;
|
|
|
|
# Node.js version (use LTS)
|
|
nodejs = pkgs.nodejs_20;
|
|
|
|
# Include devDependencies (vue-tsc, vite, etc. are needed for build)
|
|
npmFlags = [ "--include=dev" ];
|
|
makeCacheWritable = true;
|
|
|
|
# Skip Electron binary download (we're building a web app, not desktop)
|
|
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
|
|
|
|
# Environment variables for Vite build (VITE_* are embedded at build time)
|
|
# App Configuration
|
|
VITE_APP_NAME = cfg.appName;
|
|
|
|
# Nostr Configuration
|
|
VITE_NOSTR_RELAYS = builtins.toJSON cfg.nostrRelays;
|
|
VITE_ADMIN_PUBKEYS = builtins.toJSON cfg.adminPubkeys;
|
|
|
|
# API Configuration
|
|
VITE_LNBITS_BASE_URL = cfg.lnbitsBaseUrl;
|
|
VITE_API_KEY = cfg.apiKey;
|
|
VITE_LNBITS_DEBUG = if cfg.lnbitsDebug then "true" else "false";
|
|
VITE_WEBSOCKET_ENABLED = if cfg.websocketEnabled then "true" else "false";
|
|
|
|
# Lightning Address Domain
|
|
VITE_LIGHTNING_DOMAIN = cfg.lightningDomain;
|
|
|
|
# Push Notifications
|
|
VITE_VAPID_PUBLIC_KEY = cfg.vapidPublicKey;
|
|
VITE_PUSH_NOTIFICATIONS_ENABLED = if cfg.pushNotificationsEnabled then "true" else "false";
|
|
|
|
# Image Upload Configuration (pict-rs)
|
|
VITE_PICTRS_BASE_URL = cfg.pictrsBaseUrl;
|
|
|
|
# Market Configuration
|
|
VITE_MARKET_NADDR = cfg.marketNaddr;
|
|
|
|
# Additional env vars
|
|
NODE_ENV = "production";
|
|
|
|
# Explicitly add node_modules/.bin to PATH for vue-tsc, vite, etc.
|
|
buildPhase = ''
|
|
export PATH="$PWD/node_modules/.bin:$PATH"
|
|
npm run build
|
|
'';
|
|
|
|
# Install the built static files (Vite outputs to ./dist)
|
|
installPhase = ''
|
|
runHook preInstall
|
|
mkdir -p $out/share/webapp
|
|
cp -r dist/* $out/share/webapp/
|
|
runHook postInstall
|
|
'';
|
|
|
|
# Don't run npm test
|
|
doCheck = false;
|
|
|
|
meta = with lib; {
|
|
description = "AIO Community Hub - Vue 3 webapp";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
};
|
|
};
|
|
|
|
in {
|
|
options.services.webapp = {
|
|
enable = lib.mkEnableOption "AIO webapp";
|
|
|
|
gitUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "https://git.atitlan.io/aiolabs/webapp";
|
|
description = "Git repository URL for the webapp source";
|
|
};
|
|
|
|
gitRef = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "main";
|
|
example = "demo";
|
|
description = "Git branch or tag to build from";
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
example = "app.example.com";
|
|
description = "Domain name for the webapp";
|
|
};
|
|
|
|
npmDepsHash = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = lib.fakeHash;
|
|
description = ''
|
|
SHA256 hash of npm dependencies.
|
|
Run `nix-prefetch-npm-deps package-lock.json` on the webapp source
|
|
to get the correct hash.
|
|
'';
|
|
};
|
|
|
|
# App Configuration
|
|
appName = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "MyApp";
|
|
description = "Application name displayed in the UI";
|
|
};
|
|
|
|
# Nostr Configuration
|
|
nostrRelays = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ "wss://relay.damus.io" "wss://relay.snort.social" ];
|
|
description = "List of Nostr relay URLs";
|
|
};
|
|
|
|
adminPubkeys = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [];
|
|
description = "List of admin Nostr public keys (hex format)";
|
|
};
|
|
|
|
# API Configuration
|
|
lnbitsBaseUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
example = "https://lnbits.example.com";
|
|
description = "LNBits API base URL";
|
|
};
|
|
|
|
apiKey = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = "LNBits invoice/read API key";
|
|
};
|
|
|
|
lnbitsDebug = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = "Enable LNBits debug mode";
|
|
};
|
|
|
|
websocketEnabled = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Enable WebSocket for real-time updates";
|
|
};
|
|
|
|
# Lightning Address Domain
|
|
lightningDomain = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = ''
|
|
Domain used for Lightning Addresses.
|
|
Example: mydomain.com will show addresses as username@mydomain.com
|
|
'';
|
|
};
|
|
|
|
# Push Notifications
|
|
vapidPublicKey = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = "VAPID public key for push notifications";
|
|
};
|
|
|
|
pushNotificationsEnabled = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Enable push notifications";
|
|
};
|
|
|
|
# Image Upload Configuration (pict-rs)
|
|
pictrsBaseUrl = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = "Pict-rs image service base URL";
|
|
};
|
|
|
|
# Market Configuration
|
|
marketNaddr = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = "Nostr address (naddr) for the market configuration";
|
|
};
|
|
|
|
enableSSL = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Enable SSL/TLS with Let's Encrypt";
|
|
};
|
|
|
|
acmeEmail = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "";
|
|
description = "Email for Let's Encrypt certificate notifications";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# Nginx virtualHost for webapp (global nginx settings are in config/nginx.nix)
|
|
services.nginx.virtualHosts.${cfg.domain} = {
|
|
# SSL configuration
|
|
forceSSL = cfg.enableSSL;
|
|
enableACME = cfg.enableSSL;
|
|
|
|
# Serve the built webapp
|
|
root = "${webapp}/share/webapp";
|
|
|
|
locations = {
|
|
"/" = {
|
|
# Try files, fallback to index.html for SPA routing
|
|
tryFiles = "$uri $uri/ /index.html";
|
|
};
|
|
|
|
# Cache static assets aggressively
|
|
"~* \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$" = {
|
|
extraConfig = ''
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
# ACME and firewall are configured globally in config/nginx.nix
|
|
};
|
|
}
|