diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml new file mode 100644 index 0000000..518908f --- /dev/null +++ b/.github/workflows/mirror.yml @@ -0,0 +1,16 @@ +name: mirror + +on: [push] + +jobs: + mirror: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: yesolutions/mirror-action@master + with: + REMOTE: "https://codeberg.org/FyraStack/dashboard.git" + GIT_USERNAME: ${{ secrets.GIT_USERNAME }} + GIT_PASSWORD: ${{ secrets.GIT_PASSWORD }} diff --git a/.gitignore b/.gitignore index ecaf88b..d31a31b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,5 @@ vite.config.ts.timestamp-* # traces for local dev Trace-*.json + +bun.lock diff --git a/README.md b/README.md index bb5e5b0..bdf22f0 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,12 @@ 1. `pnpm install` 2. Start a Postgres server: `podman run -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres` -3. Add secrets to `.env` -4. Set up the database: `pnpm --filter stack-dashboard db:push` -5. `pnpm --filter stack-dashboard dev` +3. Copy `apps/dashboard/.env.example` to `apps/dashboard/.env` +4. Add secrets to `apps/dashboard/.env` + - Update `CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE` and set all `VPC` stuff to false + - set `BETTER_AUTH_SECRET`, `AUTUMN_SECRET` to anything +5. Set up the database: `pnpm --filter stack-dashboard db:migrate` +6. `pnpm --filter stack-dashboard dev` ### Postgres Setup @@ -21,6 +24,7 @@ - Generate Better Auth - Autumn - Postgres connection URL + - if you use the podman command(s) listed above, the connection string is `postgres://postgres:mysecretpassword@127.0.0.1:5432/postgres` - Highly recommended: - Proxmox - Optional: diff --git a/apps/dashboard/.env.example b/apps/dashboard/.env.example index 8b0ff42..a6dbd5c 100644 --- a/apps/dashboard/.env.example +++ b/apps/dashboard/.env.example @@ -14,10 +14,11 @@ BETTER_AUTH_SECRET="" # VyOS # In production, router updates are routed through the VYOS_VPC_01 / VYOS_VPC_02 # Workers VPC bindings (router 1 first, falling back to router 2 if it is offline). -# Set VYOS_USE_VPC="false" to bypass VPC and talk directly to VYOS_API_URL instead. +# VPC bindings only exist in the deployed Workers — keep VYOS_USE_VPC="false" in +# local dev so requests go directly to VYOS_API_URL instead. VYOS_API_URL="" VYOS_API_KEY="" -VYOS_USE_VPC="true" +VYOS_USE_VPC="false" # Only used for the direct (non-VPC) fallback; the VPC path terminates TLS itself. VYOS_VERIFY_SSL="false" @@ -41,18 +42,20 @@ GITHUB_CLIENT_SECRET="" # Proxmox VE backend # In production, requests are routed through the PROXMOX_VPC Workers VPC binding, -# which terminates TLS. Set PROXMOX_USE_VPC="false" to bypass VPC and talk directly -# to PROXMOX_API_URL (self-signed certs are accepted automatically outside production). +# which terminates TLS. VPC bindings only exist in the deployed Workers — keep +# PROXMOX_USE_VPC="false" in local dev so requests go directly to PROXMOX_API_URL +# (self-signed certs are accepted automatically outside production). PROXMOX_API_URL="https://pve.example.com:8006" PROXMOX_TOKEN_ID="root@pam!stack" PROXMOX_TOKEN_SECRET="" -PROXMOX_USE_VPC="true" +PROXMOX_USE_VPC="false" PROXMOX_VM_FIREWALL_SECURITY_GROUP="" # In production, snippet uploads are routed through the SNIPPETS Workers VPC binding. -# Set PROXMOX_SNIPPETS_USE_VPC="false" to bypass VPC and talk directly to the endpoint -# below (PROXMOX_SNIPPETS_ENDPOINT_VERIFY_SSL then governs TLS for that direct path). -PROXMOX_SNIPPETS_USE_VPC="true" +# VPC bindings only exist in the deployed Workers — keep this "false" in local dev to +# talk directly to the endpoint below (PROXMOX_SNIPPETS_ENDPOINT_VERIFY_SSL then +# governs TLS for that direct path). +PROXMOX_SNIPPETS_USE_VPC="false" PROXMOX_SNIPPETS_ENDPOINT_URL="https://pxmx-01.example:8005" PROXMOX_SNIPPETS_ENDPOINT_USERNAME="pvecic" PROXMOX_SNIPPETS_ENDPOINT_PASSWORD="change-me" diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 0af4dbc..09ca21d 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -7,7 +7,7 @@ "dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 vite dev", "build": "vite build", "preview": "vite preview", - "cf:dev": "pnpm run build && wrangler dev --local-protocol http", + "cf:dev": "pnpm run build && wrangler dev -c wrangler.local.jsonc --local-protocol http", "cf:dev:remote": "pnpm run build && wrangler dev --remote", "cf:deploy": "wrangler deploy --env=\"\"", "cf:deploy:preview": "pnpm run build && wrangler deploy --env preview", diff --git a/apps/dashboard/src/lib/name-generator.ts b/apps/dashboard/src/lib/name-generator.ts new file mode 100644 index 0000000..19c1a49 --- /dev/null +++ b/apps/dashboard/src/lib/name-generator.ts @@ -0,0 +1,8 @@ +const choices = [ + ["kitten", "cat", "neko", "puppy", "dog", "doggy"], + ["box", "stack", "rack", "server", "node"], +]; + +const choose = (i: int) => choices[i][Math.floor(Math.random() * choices[i].length)]; + +export const generateServerName = () => choose(0) + choose(1); diff --git a/apps/dashboard/src/lib/server/name-generator.ts b/apps/dashboard/src/lib/server/name-generator.ts new file mode 100644 index 0000000..19c1a49 --- /dev/null +++ b/apps/dashboard/src/lib/server/name-generator.ts @@ -0,0 +1,8 @@ +const choices = [ + ["kitten", "cat", "neko", "puppy", "dog", "doggy"], + ["box", "stack", "rack", "server", "node"], +]; + +const choose = (i: int) => choices[i][Math.floor(Math.random() * choices[i].length)]; + +export const generateServerName = () => choose(0) + choose(1); diff --git a/apps/dashboard/src/routes/(app)/projects/[projectid]/servers/create/+page.svelte b/apps/dashboard/src/routes/(app)/projects/[projectid]/servers/create/+page.svelte index 655625d..145b3dc 100644 --- a/apps/dashboard/src/routes/(app)/projects/[projectid]/servers/create/+page.svelte +++ b/apps/dashboard/src/routes/(app)/projects/[projectid]/servers/create/+page.svelte @@ -26,8 +26,10 @@ EyeOff, HardDriveUpload, Plus, - X + X, + Dices } from '@lucide/svelte'; + import { generateServerName } from '$lib/name-generator'; type PageData = { currentProject?: { id: string } | null; @@ -123,7 +125,10 @@ const ipv6Available = $derived(Boolean(data.ipamAvailability?.ipv6.available)); const bothNetworksAvailable = $derived(ipv4Available && ipv6Available); - let serverName = $state(''); + let serverName = $state(generateServerName()); + function regenerateServerName() { + serverName = generateServerName(); + } let selectedImageId = $state(null); let selectedImageVersion = $state(null); let selectedPlanId = $state(null); @@ -417,12 +422,15 @@ >Name -
+
+
diff --git a/apps/dashboard/svelte.config.js b/apps/dashboard/svelte.config.js index 2ba3e3d..bb36f98 100644 --- a/apps/dashboard/svelte.config.js +++ b/apps/dashboard/svelte.config.js @@ -8,7 +8,11 @@ const config = { } }, kit: { - adapter: adapter(), + adapter: adapter({ + platformProxy: { + configPath: 'wrangler.local.jsonc' + } + }), experimental: { remoteFunctions: true } diff --git a/apps/dashboard/wrangler.local.jsonc b/apps/dashboard/wrangler.local.jsonc new file mode 100644 index 0000000..98980c6 --- /dev/null +++ b/apps/dashboard/wrangler.local.jsonc @@ -0,0 +1,50 @@ +{ + "$schema": "../../node_modules/wrangler/config-schema.json", + "name": "stack-dashboard", + "main": ".svelte-kit/cloudflare/_worker.js", + "compatibility_date": "2026-04-05", + "compatibility_flags": ["nodejs_compat"], + "assets": { + "binding": "ASSETS", + "directory": ".svelte-kit/cloudflare", + "run_worker_first": [ + "/", + "/_app/remote/*", + "/api/*", + "/admin/*", + "/projects/*", + "/login*", + "/register*", + "/signup*", + "/accept-invitation/*" + ] + }, + "vars": { + "ORIGIN": "http://localhost:5173", + "EMAIL_FROM_ADDRESS": "no-reply@example.com", + "EMAIL_FROM_NAME": "Fyra Stack", + "EMAIL_REPLY_TO": "support@example.com", + "AUTUMN_DEFAULT_PLAN_ID": "stack", + "AUTUMN_SERVER_ENTITY_FEATURE_ID": "active_servers", + "VYOS_USE_VPC": "false", + "PROXMOX_USE_VPC": "false", + "PROXMOX_SNIPPETS_USE_VPC": "false" + }, + "hyperdrive": [ + { + "binding": "HYPERDRIVE", + "id": "25228ed6f77e49fb8041aed12879327d" + } + ], + "kv_namespaces": [ + { + "binding": "FEATURE_FLAGS", + "id": "0ad17de8747747bca1975d473e66e295" + } + ], + "send_email": [ + { + "name": "EMAIL" + } + ] +}