Spaces:
Running
Running
feat: vendor Plus Jakarta Sans fonts and patch layouts to resolve build-time network constraints, update health-server proxy logic, and correct UptimeRobot interval units.
Browse files- Dockerfile +18 -0
- health-server.js +5 -14
- setup-uptimerobot.sh +2 -2
- start.sh +1 -0
- vendor/fonts/PlusJakartaSans-500-italic.woff2 +0 -0
- vendor/fonts/PlusJakartaSans-500-normal.woff2 +0 -0
- vendor/fonts/PlusJakartaSans-600-italic.woff2 +0 -0
- vendor/fonts/PlusJakartaSans-600-normal.woff2 +0 -0
- vendor/patch-jakarta-font.js +29 -0
Dockerfile
CHANGED
|
@@ -58,6 +58,24 @@ ENV SENTRY_DSN="" \
|
|
| 58 |
# Changing patches won't bust the pnpm install cache layer.
|
| 59 |
RUN pnpm install --frozen-lockfile=false
|
| 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
# Patch Next.js config (after install β see above).
|
| 62 |
# 1. basePath/assetPrefix=/app β Postiz UI at /app; HuggingPost dashboard owns /
|
| 63 |
# 2. productionBrowserSourceMaps: false β smaller build output
|
|
|
|
| 58 |
# Changing patches won't bust the pnpm install cache layer.
|
| 59 |
RUN pnpm install --frozen-lockfile=false
|
| 60 |
|
| 61 |
+
# Vendor Plus Jakarta Sans β HF Space cannot reach fonts.gstatic.com.
|
| 62 |
+
# Postiz upstream imports `Plus_Jakarta_Sans` from `next/font/google` in two
|
| 63 |
+
# layout files, which forces a build-time fetch from gstatic. HF egress to
|
| 64 |
+
# gstatic is blocked/throttled, so `next build` retry-loops indefinitely.
|
| 65 |
+
# We ship 4 woff2 variants in the image and rewrite both layouts to use
|
| 66 |
+
# `next/font/local` (zero network at build).
|
| 67 |
+
COPY vendor/fonts/PlusJakartaSans-500-normal.woff2 \
|
| 68 |
+
vendor/fonts/PlusJakartaSans-500-italic.woff2 \
|
| 69 |
+
vendor/fonts/PlusJakartaSans-600-normal.woff2 \
|
| 70 |
+
vendor/fonts/PlusJakartaSans-600-italic.woff2 \
|
| 71 |
+
apps/frontend/src/fonts/
|
| 72 |
+
COPY vendor/patch-jakarta-font.js /tmp/patch-jakarta-font.js
|
| 73 |
+
RUN node /tmp/patch-jakarta-font.js \
|
| 74 |
+
&& grep -q "next/font/local" "apps/frontend/src/app/(app)/layout.tsx" \
|
| 75 |
+
&& grep -q "next/font/local" "apps/frontend/src/app/(extension)/layout.tsx" \
|
| 76 |
+
&& ! grep -rq "next/font/google" apps/frontend/src/app/ \
|
| 77 |
+
|| (echo "JAKARTA PATCH FAILED β layout.tsx shape changed upstream"; exit 1)
|
| 78 |
+
|
| 79 |
# Patch Next.js config (after install β see above).
|
| 80 |
# 1. basePath/assetPrefix=/app β Postiz UI at /app; HuggingPost dashboard owns /
|
| 81 |
# 2. productionBrowserSourceMaps: false β smaller build output
|
health-server.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
// Routing rules (in order):
|
| 7 |
// /health, /status, /uptimerobot/setup β handled here
|
| 8 |
// / (exact) β HuggingPost dashboard HTML
|
| 9 |
-
// /app or /app/*
|
| 10 |
// /_next/* or /static/* β 301 redirect to /app/<same path>
|
| 11 |
// (catches asset URLs Next.js may emit
|
| 12 |
// without basePath in edge cases)
|
|
@@ -569,19 +569,10 @@ const server = http.createServer((req, res) => {
|
|
| 569 |
return;
|
| 570 |
}
|
| 571 |
|
| 572 |
-
// ββ /app
|
| 573 |
-
//
|
| 574 |
-
//
|
| 575 |
-
|
| 576 |
-
// Next.js middleware will redirect to /app/launches/ if already logged in.
|
| 577 |
-
if (pathname === "/app" || pathname === "/app/") {
|
| 578 |
-
res.writeHead(302, { Location: "/app/auth/" });
|
| 579 |
-
res.end();
|
| 580 |
-
return;
|
| 581 |
-
}
|
| 582 |
-
|
| 583 |
-
// ββ /app/* β serve public static files from disk, proxy the rest ββββββββ
|
| 584 |
-
if (pathname.startsWith("/app/")) {
|
| 585 |
const stripped = pathname.slice("/app".length) || "/";
|
| 586 |
const query = parsedUrl.search || "";
|
| 587 |
|
|
|
|
| 6 |
// Routing rules (in order):
|
| 7 |
// /health, /status, /uptimerobot/setup β handled here
|
| 8 |
// / (exact) β HuggingPost dashboard HTML
|
| 9 |
+
// /app, /app/ or /app/* β Postiz (nginx :5000), /app prefix stripped
|
| 10 |
// /_next/* or /static/* β 301 redirect to /app/<same path>
|
| 11 |
// (catches asset URLs Next.js may emit
|
| 12 |
// without basePath in edge cases)
|
|
|
|
| 569 |
return;
|
| 570 |
}
|
| 571 |
|
| 572 |
+
// ββ /app, /app/ and /app/* β proxy to nginx (Next.js handles routing) ββββ
|
| 573 |
+
// Do NOT short-circuit /app/ to /app/auth/ here β Next.js middleware does
|
| 574 |
+
// the right thing: auth cookie present β /launches, absent β /auth/.
|
| 575 |
+
if (pathname === "/app" || pathname.startsWith("/app/")) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 576 |
const stripped = pathname.slice("/app".length) || "/";
|
| 577 |
const query = parsedUrl.search || "";
|
| 578 |
|
setup-uptimerobot.sh
CHANGED
|
@@ -10,7 +10,7 @@ set -euo pipefail
|
|
| 10 |
# Optional:
|
| 11 |
# - UPTIMEROBOT_MONITOR_NAME: friendly name for the monitor
|
| 12 |
# - UPTIMEROBOT_ALERT_CONTACTS: dash-separated alert contact IDs, e.g. "123456-789012"
|
| 13 |
-
# - UPTIMEROBOT_INTERVAL: monitoring interval in
|
| 14 |
|
| 15 |
API_URL="https://api.uptimerobot.com/v2"
|
| 16 |
API_KEY="${UPTIMEROBOT_API_KEY:-}"
|
|
@@ -36,7 +36,7 @@ SPACE_HOST_CLEAN="${SPACE_HOST_CLEAN%%/*}"
|
|
| 36 |
|
| 37 |
MONITOR_URL="https://${SPACE_HOST_CLEAN}/health"
|
| 38 |
MONITOR_NAME="${UPTIMEROBOT_MONITOR_NAME:-HuggingPost ${SPACE_HOST_CLEAN}}"
|
| 39 |
-
INTERVAL="${UPTIMEROBOT_INTERVAL:-
|
| 40 |
|
| 41 |
echo "Checking existing UptimeRobot monitors for ${MONITOR_URL}..."
|
| 42 |
MONITORS_RESPONSE=$(curl -sS -X POST "${API_URL}/getMonitors" \
|
|
|
|
| 10 |
# Optional:
|
| 11 |
# - UPTIMEROBOT_MONITOR_NAME: friendly name for the monitor
|
| 12 |
# - UPTIMEROBOT_ALERT_CONTACTS: dash-separated alert contact IDs, e.g. "123456-789012"
|
| 13 |
+
# - UPTIMEROBOT_INTERVAL: monitoring interval in seconds (default: 300 = 5 min; min: 30)
|
| 14 |
|
| 15 |
API_URL="https://api.uptimerobot.com/v2"
|
| 16 |
API_KEY="${UPTIMEROBOT_API_KEY:-}"
|
|
|
|
| 36 |
|
| 37 |
MONITOR_URL="https://${SPACE_HOST_CLEAN}/health"
|
| 38 |
MONITOR_NAME="${UPTIMEROBOT_MONITOR_NAME:-HuggingPost ${SPACE_HOST_CLEAN}}"
|
| 39 |
+
INTERVAL="${UPTIMEROBOT_INTERVAL:-300}"
|
| 40 |
|
| 41 |
echo "Checking existing UptimeRobot monitors for ${MONITOR_URL}..."
|
| 42 |
MONITORS_RESPONSE=$(curl -sS -X POST "${API_URL}/getMonitors" \
|
start.sh
CHANGED
|
@@ -69,6 +69,7 @@ export PGPASSWORD="${DB_PASSWORD}"
|
|
| 69 |
export DATABASE_URL="${DATABASE_URL:-postgresql://postiz:${DB_PASSWORD}@localhost:5432/postiz}"
|
| 70 |
export REDIS_URL="${REDIS_URL:-redis://localhost:6379}"
|
| 71 |
export FRONTEND_URL="${FRONTEND_URL:-${PUBLIC_URL}}"
|
|
|
|
| 72 |
export NEXT_PUBLIC_BACKEND_URL="${NEXT_PUBLIC_BACKEND_URL:-${PUBLIC_URL}/app/api}"
|
| 73 |
export BACKEND_INTERNAL_URL="${BACKEND_INTERNAL_URL:-http://localhost:3000}"
|
| 74 |
export STORAGE_PROVIDER="${STORAGE_PROVIDER:-local}"
|
|
|
|
| 69 |
export DATABASE_URL="${DATABASE_URL:-postgresql://postiz:${DB_PASSWORD}@localhost:5432/postiz}"
|
| 70 |
export REDIS_URL="${REDIS_URL:-redis://localhost:6379}"
|
| 71 |
export FRONTEND_URL="${FRONTEND_URL:-${PUBLIC_URL}}"
|
| 72 |
+
export MAIN_URL="${MAIN_URL:-${PUBLIC_URL}}"
|
| 73 |
export NEXT_PUBLIC_BACKEND_URL="${NEXT_PUBLIC_BACKEND_URL:-${PUBLIC_URL}/app/api}"
|
| 74 |
export BACKEND_INTERNAL_URL="${BACKEND_INTERNAL_URL:-http://localhost:3000}"
|
| 75 |
export STORAGE_PROVIDER="${STORAGE_PROVIDER:-local}"
|
vendor/fonts/PlusJakartaSans-500-italic.woff2
ADDED
|
Binary file (13.1 kB). View file
|
|
|
vendor/fonts/PlusJakartaSans-500-normal.woff2
ADDED
|
Binary file (12.3 kB). View file
|
|
|
vendor/fonts/PlusJakartaSans-600-italic.woff2
ADDED
|
Binary file (13 kB). View file
|
|
|
vendor/fonts/PlusJakartaSans-600-normal.woff2
ADDED
|
Binary file (12.2 kB). View file
|
|
|
vendor/patch-jakarta-font.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const fs = require('fs');
|
| 2 |
+
|
| 3 |
+
const files = [
|
| 4 |
+
'apps/frontend/src/app/(app)/layout.tsx',
|
| 5 |
+
'apps/frontend/src/app/(extension)/layout.tsx',
|
| 6 |
+
];
|
| 7 |
+
|
| 8 |
+
const importOld = "import { Plus_Jakarta_Sans } from 'next/font/google';";
|
| 9 |
+
const importNew = "import localFont from 'next/font/local';";
|
| 10 |
+
const callRegex = /const jakartaSans = Plus_Jakarta_Sans\(\{[\s\S]*?\}\);/;
|
| 11 |
+
const callNew = `const jakartaSans = localFont({
|
| 12 |
+
src: [
|
| 13 |
+
{ path: '../../fonts/PlusJakartaSans-500-normal.woff2', weight: '500', style: 'normal' },
|
| 14 |
+
{ path: '../../fonts/PlusJakartaSans-500-italic.woff2', weight: '500', style: 'italic' },
|
| 15 |
+
{ path: '../../fonts/PlusJakartaSans-600-normal.woff2', weight: '600', style: 'normal' },
|
| 16 |
+
{ path: '../../fonts/PlusJakartaSans-600-italic.woff2', weight: '600', style: 'italic' },
|
| 17 |
+
],
|
| 18 |
+
display: 'swap',
|
| 19 |
+
});`;
|
| 20 |
+
|
| 21 |
+
for (const f of files) {
|
| 22 |
+
const src = fs.readFileSync(f, 'utf8');
|
| 23 |
+
if (!src.includes(importOld) || !callRegex.test(src)) {
|
| 24 |
+
console.error(`PATCH FAIL: ${f} β Plus_Jakarta_Sans pattern not found`);
|
| 25 |
+
process.exit(1);
|
| 26 |
+
}
|
| 27 |
+
fs.writeFileSync(f, src.replace(importOld, importNew).replace(callRegex, callNew));
|
| 28 |
+
console.log(`patched ${f}`);
|
| 29 |
+
}
|