Skip to content

Commit 75e78d4

Browse files
Merge pull request #122 from NodeByteHosting/development
chore: sync development → nightly (2026-07-06)
2 parents 1b5e412 + 6858586 commit 75e78d4

54 files changed

Lines changed: 1896 additions & 807 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,67 @@ All notable changes to the NodeByte Hosting website will be documented in this f
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [3.6.0] - 2026-07-04
9+
10+
### Added
11+
12+
- **Dedicated Server Hosting** — new `/dedicated` product category backed by live Paymenter billing data
13+
- `packages/core/types/servers/dedicated.ts``DedicatedPlanSpec` interface; `cores` is optional (physical cores, not vCPU), `storageDescription` holds the raw drive label (e.g. `"2 × 1 TB NVMe SSD (RAID 1)"`) for multi-drive configurations
14+
- `packages/core/products/billing-service.ts``getDedicatedPlans(categorySlug)` function following the same billing-service pattern as VPS and game plans
15+
- `packages/ui/components/Layouts/Dedicated/dedicated-hub.tsx` — listing page with AMD/Intel hardware filter, price sort, "Bare Metal" and hardware badges, IPMI/dedicated feature callouts, and a custom/enterprise CTA
16+
- `app/dedicated/page.tsx` — server component fetching from the `dedicated-servers` billing category
17+
- Navigation — Dedicated Servers section added to both desktop and mobile Services dropdowns, below VPS Servers
18+
- Footer — Dedicated Servers link added to the Services column
19+
- `packages/core/constants/services.ts` — Dedicated Servers entry added to `SERVICE_CATEGORIES` for the homepage service cards (amber palette, Cpu icon)
20+
- `translations/templates/en.json``services.dedicated.*` and `footer.services.dedicatedServers` translation keys added
21+
22+
- **Knowledge Base Subcategory Support** — the KB now supports arbitrary nesting (e.g. `games → minecraft → troubleshooting`) driven entirely by the filesystem
23+
- `app/kb/[...path]/page.tsx` — unified catch-all route replacing the old fixed `[category]` and `[category]/[article]` routes; calls `resolvePath()` to decide whether to render a category page or an article page
24+
- `packages/kb/lib/kb.ts` — full rewrite: `getCategories(parentPath?)` recurses into subdirectories, `getCategoryAtPath()` traverses the tree, `getSidebarTree()` / `buildSidebarItem()` build the full nested sidebar, `getAllPaths()` returns every valid path array for `generateStaticParams`
25+
- `packages/kb/components/kb-sidebar.tsx` — recursive `SidebarNode` component with depth-aware indentation; auto-expands the branch matching the current pathname
26+
- `packages/kb/components/kb-category-card.tsx``href` now uses the full category path; badge shows recursive `totalCount`
27+
- `packages/kb/components/kb-article-card.tsx``href` uses `categoryPath` (full relative path)
28+
- `packages/kb/components/kb-article.tsx` — prev/next links use full `categoryPath`
29+
- `packages/kb/components/kb-search.tsx` — search result links use full `categoryPath`
30+
- KB content restructured under `packages/kb/content/games/minecraft/` and `packages/kb/content/games/hytale/` subdirectories
31+
32+
- **Billing-Native Currency Prices** — the website now uses exact prices from the Paymenter billing panel per currency instead of converting from a GBP exchange rate
33+
- `packages/core/lib/bytepay.ts``getPricesMap(product)` returns `Record<string, number>` mapping every currency code to its monthly price from the product's recurring plan
34+
- `packages/ui/components/ui/price.tsx``Price` component accepts an optional `prices` prop; uses `format(prices[currency])` (exact billing price) when available, falls back to `convertAndFormat(amountGBP)` (exchange rate)
35+
- `packages/core/types/servers/game.ts`, `vps.ts`, `dedicated.ts``prices?: Record<string, number>` field added to all plan spec interfaces
36+
- `billing-service.ts` — all three plan fetchers (`getGamePlans`, `getVpsPlans`, `getDedicatedPlans`) populate `prices` from `getPricesMap()`
37+
- VPS Hub, all game pages — `prices` prop threaded through to `<Price>` components
38+
39+
### Changed
40+
41+
- **Spec Parser Improvements** (`packages/core/lib/spec-parser.ts`) — backward-compatible improvements that benefit VPS, game, and dedicated server parsing
42+
- **CPU core count** — now falls back to inline patterns: `"8 cores and 16 threads"` (any position in text) and named multipliers (`"Octa-Core"` → 8, `"Quad-Core"` → 4, `"Dual-Core"` → 2, etc.)
43+
- **Storage** — handles TB drives: `"2 x 1 TB NVMe SSD"``storageGB = 1024`; extracts `storageDescription` (the raw drive label before the colon, e.g. `"2 × 512 GB NVMe SSD (Gen 4)"`) for use in place of a bare number on dedicated server cards
44+
- **Bandwidth detection** — no longer false-matches storage descriptions; TB references are only counted as bandwidth when paired with `outbound`, `traffic`, or `bandwidth` keywords; `"Unlimited Outbound Bandwidth"` correctly resolves to `null` (unmetered)
45+
- **Intel CPU model** — regex expanded from Xeon-only to also match `"Intel® Core™ Ultra 7 265"` and `"Intel® Core™ i9"` families
46+
- **AMD Ryzen model** — regex extended to capture PRO variants (`"Ryzen 7 PRO 8700GE"`)
47+
48+
### Performance
49+
50+
- **Decorative blur orbs replaced with CSS radial-gradients** — all `blur-[120px]`/`blur-[100px]` divs with `animate-pulse` replaced by a single `<div style={{ background: "radial-gradient(...)" }}>` across every affected component; eliminates GPU compositing layers and per-frame repaints that were causing slow load times on Apple WebKit/Safari
51+
- `packages/ui/components/Layouts/Home/hero.tsx`
52+
- `packages/ui/components/Layouts/About/about-page.tsx`
53+
- `packages/ui/components/Layouts/Contact/contact.tsx`
54+
- `packages/ui/components/Layouts/Error/error-page.tsx`
55+
- `packages/ui/components/Layouts/Error/not-found-page.tsx`
56+
- `packages/ui/components/Layouts/Nodes/nodes-client.tsx`
57+
- `packages/ui/components/Layouts/VPS/vps-hub.tsx`
58+
- `packages/ui/components/Layouts/VPS/vps-hero.tsx` (conditional AMD/Intel colour palette preserved via inline style)
59+
- **Navbar `backdrop-blur-xl``backdrop-blur-md`** — reduces the full-width blur filter cost on the scrolled navbar state without a visible quality difference
60+
- **Theme toggle mobile cutoff fixed**`DropdownMenuContent` now has `max-h-[85svh] flex flex-col`; inner theme scroll container changed to `flex-1 min-h-0 overflow-y-auto` so all themes are reachable on small screens
61+
62+
### Fixed
63+
64+
- **`packages/kb/content/billing/_meta.json` SyntaxError** — file ended with a stray `0` instead of `}`; fixed to valid JSON
65+
- **Stale `.next/types` build cache** — after deleting the old `[category]` and `[category]/[article]` KB routes the build cache still referenced them; resolved by deleting `.next/types` before the next build
66+
67+
---
68+
869
## [3.5.4] - 2026-05-30
970

1071
### Added
@@ -644,5 +705,6 @@ Initial Next.js 15 website with App Router, shadcn/ui components, and multi-them
644705

645706
---
646707

708+
[3.6.0]: https://github.com/NodeByteHosting/website/compare/v3.5.4...v3.6.0
647709
[3.1.0]: https://github.com/NodeByteHosting/website/compare/v3.0.0...v3.1.0
648710
[3.0.0]: https://github.com/NodeByteHosting/website/releases/tag/v3.0.0

app/api/billing-debug/route.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { fetchAllBillingProducts } from "@/packages/core/lib/bytepay"
2+
3+
export const dynamic = "force-dynamic"
4+
5+
export async function GET(request: Request) {
6+
if (process.env.NODE_ENV !== "development") {
7+
return Response.json({ error: "Not available in production" }, { status: 403 })
8+
}
9+
10+
const { searchParams } = new URL(request.url)
11+
const category = searchParams.get("category")
12+
13+
const products = await fetchAllBillingProducts()
14+
const filtered = category ? products.filter((p) => p.categorySlug === category) : products
15+
16+
const summary = filtered.map((p) => ({
17+
id: p.id,
18+
name: p.name,
19+
slug: p.slug,
20+
categorySlug: p.categorySlug,
21+
hidden: p.hidden,
22+
stock: p.stock,
23+
gbpMonthly:
24+
p.plans
25+
.find((pl) => pl.type === "recurring" && pl.billingPeriod === 1 && pl.billingUnit === "month")
26+
?.prices.find((pr) => pr.currencyCode === "GBP")?.price ?? null,
27+
description: p.description,
28+
}))
29+
30+
return Response.json({ count: summary.length, products: summary })
31+
}

app/dedicated/page.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { Metadata } from "next"
2+
import { DedicatedHub } from "@/packages/ui/components/Layouts/Dedicated/dedicated-hub"
3+
import { getDedicatedPlans } from "@/packages/core/products/billing-service"
4+
5+
export const metadata: Metadata = {
6+
title: "Dedicated Servers",
7+
description:
8+
"Physical bare-metal servers with fully dedicated CPU cores, enterprise storage, and IPMI out-of-band access. Zero resource contention, maximum performance.",
9+
}
10+
11+
export default async function DedicatedPage() {
12+
const plans = await getDedicatedPlans("dedicated-servers")
13+
return <DedicatedHub plans={plans} />
14+
}

app/games/hytale/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ import type { Metadata } from "next"
77
import { getTranslations } from "next-intl/server"
88
import { LINKS } from "@/packages/core/constants/links"
99
import {
10-
HYTALE_PLANS,
1110
HYTALE_PLAN_DISPLAY,
1211
HYTALE_PLAN_STATIC_FEATURES,
1312
HYTALE_FEATURES,
1413
HYTALE_FAQS,
1514
HYTALE_HERO_FEATURES,
1615
HYTALE_CONFIG,
1716
} from "@/packages/core/constants/game"
18-
import { applyGamePlanOverrides } from "@/packages/core/products/server"
17+
import { getGamePlans } from "@/packages/core/products/billing-service"
1918

2019
export const metadata: Metadata = {
2120
title: "Hytale Server Hosting",
@@ -25,12 +24,13 @@ export const metadata: Metadata = {
2524
export default async function HytalePage() {
2625
const t = await getTranslations()
2726

28-
const plans = applyGamePlanOverrides("hytale", HYTALE_PLANS).map((plan) => {
27+
const plans = (await getGamePlans("hytale")).map((plan) => {
2928
const display = HYTALE_PLAN_DISPLAY[plan.id as keyof typeof HYTALE_PLAN_DISPLAY]
3029
return {
3130
name: display.name,
3231
description: display.description,
3332
priceGBP: plan.priceGBP,
33+
prices: plan.prices,
3434
period: t("pricing.perMonth"),
3535
popular: plan.popular,
3636
url: plan.url,

app/games/minecraft/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import { GameFAQ } from "@/packages/ui/components/Layouts/Games/game-faq"
77
import { getTranslations } from "next-intl/server"
88
import { LINKS } from "@/packages/core/constants/links"
99
import {
10-
MINECRAFT_PLANS,
1110
MINECRAFT_PLAN_FEATURE_KEYS,
1211
MINECRAFT_FEATURE_KEYS,
1312
MINECRAFT_FAQ_KEYS,
1413
MINECRAFT_HERO_FEATURES,
1514
MINECRAFT_CONFIG,
1615
} from "@/packages/core/constants/game"
17-
import { applyGamePlanOverrides } from "@/packages/core/products/server"
16+
import { getGamePlans } from "@/packages/core/products/billing-service"
1817

1918
export const metadata: Metadata = {
2019
title: "Minecraft Server Hosting",
@@ -24,10 +23,11 @@ export const metadata: Metadata = {
2423
export default async function MinecraftPage() {
2524
const t = await getTranslations()
2625

27-
const plans = applyGamePlanOverrides("minecraft", MINECRAFT_PLANS).map((plan) => ({
26+
const plans = (await getGamePlans("minecraft")).map((plan) => ({
2827
name: t(`games.minecraft.plans.${plan.id}.name`),
2928
description: t(`games.minecraft.plans.${plan.id}.description`),
3029
priceGBP: plan.priceGBP,
30+
prices: plan.prices,
3131
period: t("pricing.perMonth"),
3232
popular: plan.popular,
3333
location: plan.location,

app/games/rust/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import { GameFAQ } from "@/packages/ui/components/Layouts/Games/game-faq"
77
import { getTranslations } from "next-intl/server"
88
import { LINKS } from "@/packages/core/constants/links"
99
import {
10-
RUST_PLANS,
1110
RUST_PLAN_FEATURE_KEYS,
1211
RUST_FEATURE_KEYS,
1312
RUST_FAQ_KEYS,
1413
RUST_HERO_FEATURES,
1514
RUST_CONFIG,
1615
} from "@/packages/core/constants/game"
17-
import { applyGamePlanOverrides } from "@/packages/core/products/server"
16+
import { getGamePlans } from "@/packages/core/products/billing-service"
1817

1918
export const metadata: Metadata = {
2019
title: "Rust Server Hosting",
@@ -24,10 +23,11 @@ export const metadata: Metadata = {
2423
export default async function RustPage() {
2524
const t = await getTranslations()
2625

27-
const plans = applyGamePlanOverrides("rust", RUST_PLANS).map((plan) => ({
26+
const plans = (await getGamePlans("rust")).map((plan) => ({
2827
name: t(`games.rust.plans.${plan.id}.name`),
2928
description: t(`games.rust.plans.${plan.id}.description`),
3029
priceGBP: plan.priceGBP,
30+
prices: plan.prices,
3131
period: t("pricing.perMonth"),
3232
popular: plan.popular,
3333
location: plan.location,

0 commit comments

Comments
 (0)