Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/generate-openapi-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ name: Generate OpenAPI artifact
on:
workflow_call: {}

permissions:
contents: read

jobs:
generate:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion apps/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM node:26-alpine@sha256:2d984a15c9b54fd0aeb608b8e0d0d83529eb34d2966db27a1fb4f1edc3d298a3 AS build

RUN npm install -g corepack && corepack enable && corepack prepare pnpm@11.25.0 --activate
RUN npm install -g corepack@0.36.0 && corepack enable && corepack prepare pnpm@11.25.0 --activate
WORKDIR /app

# Manifests first for layer caching (all workspace manifests are required
Expand Down
2 changes: 1 addition & 1 deletion apps/web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM node:26-alpine@sha256:2d984a15c9b54fd0aeb608b8e0d0d83529eb34d2966db27a1fb4f1edc3d298a3 AS build

RUN npm install -g corepack && corepack enable && corepack prepare pnpm@11.25.0 --activate
RUN npm install -g corepack@0.36.0 && corepack enable && corepack prepare pnpm@11.25.0 --activate
WORKDIR /app

COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
Expand Down
26 changes: 13 additions & 13 deletions apps/web/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,32 @@
/* Light — "le programme" (warm manila paper). Cards are pure white so they
lift cleanly off the cream shell; the border carries the separation,
not background saturation — a saturated bg read as dirty/kraft. */
--bg: #f2ebdc;
--bg: #f7f5f3;
--surface: #ffffff;
--surface-2: #ece3ce;
--border: #d9cba9;
--surface-2: #edeae3;
--border: #d3c7a8;
--fg: #1c1712;
--dim: #6b6354;
--accent: #96570a;
--accent: #8e620b;
--accent-fg: #ffffff;
--btn: #1c1712;
--btn-fg: #ffffff;
--success: #2fa070;
--danger: #c9445e;
--warning: #c1650f;
--success: #257e58;
--danger: #c73c57;
--warning: #ab590d;
/* Stats: one hue per domain, fixed order, CVD-validated — never cycled,
never reused for anything else. Sub-splits within a domain (e.g.
movie/series/anime) tint this hue rather than borrowing another
domain's color. */
--stat-media: #b07e10;
--stat-games: #0e8f9e;
--stat-books: #c7508e;
--stat-music: #3e6fc9;
--stat-media: #91680d;
--stat-games: #0c7a87;
--stat-books: #be3d80;
--stat-music: #3b6dc8;
/* Achievement tiers ([G5]). One ring color per tier, never reused for
anything else — same rule as the per-domain stat hues above. */
--tier-bronze: #8a5423;
--tier-silver: #6e7683;
--tier-gold: #96570a;
--tier-silver: #68707c;
--tier-gold: #8e620b;
color-scheme: light;
}

Expand Down
7 changes: 7 additions & 0 deletions apps/web/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// Vite's own ambient types (vite/client.d.ts) declare `*.ico` but not the
// `?inline` variant used by favicon.ico's +server.ts route.
declare module "*.ico?inline" {
const src: string;
export default src;
}

// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces
declare global {
Expand Down
15 changes: 15 additions & 0 deletions apps/web/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { paraglideMiddleware } from "$lib/paraglide/server.js";
import type { Handle } from "@sveltejs/kit";

// Caddy (docker/Caddyfile) sets these same two headers at the edge for the
// hosted VPS, but a self-host install running this container directly
// (no reverse proxy, or one without equivalent headers) would otherwise
// ship with neither - set them here too so the app is protected either way.
// CSP stays out of scope here (see docker/Caddyfile's Report-Only comment).
const SECURITY_HEADERS = {
"X-Frame-Options": "DENY",
"X-Content-Type-Options": "nosniff",
};

export const handle: Handle = ({ event, resolve }) =>
paraglideMiddleware(event.request, async ({ request, locale }) => {
event.request = request;
Expand All @@ -9,5 +19,10 @@ export const handle: Handle = ({ event, resolve }) =>
html.replaceAll("%paraglide.lang%", locale),
});
response.headers.append("Vary", "Accept-Language, Cookie");

for (const [name, value] of Object.entries(SECURITY_HEADERS)) {
response.headers.set(name, value);
}

return response;
});
File renamed without changes.
18 changes: 18 additions & 0 deletions apps/web/src/routes/favicon.ico/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import favicon from "$lib/assets/favicon.ico?inline";
import type { RequestHandler } from "./$types";

// sirv (adapter-node's static file server) resolves content types via
// mrmime, which has no `.ico` entry — a plain static/favicon.ico is served
// with an empty Content-Type (see the ZAP "Content-Type header missing"
// finding). Routing it through a +server.ts instead lets us set it
// explicitly. `?inline` forces Vite to always emit a base64 data: URI for
// this import, regardless of its size vs the default inlining threshold.
const bytes = Buffer.from(favicon.slice(favicon.indexOf(",") + 1), "base64");

Check warning on line 10 in apps/web/src/routes/favicon.ico/+server.ts

View check run for this annotation

Codecov / codecov/patch

apps/web/src/routes/favicon.ico/+server.ts#L10

Added line #L10 was not covered by tests

export const GET: RequestHandler = () =>
new Response(bytes, {

Check warning on line 13 in apps/web/src/routes/favicon.ico/+server.ts

View check run for this annotation

Codecov / codecov/patch

apps/web/src/routes/favicon.ico/+server.ts#L12-L13

Added lines #L12 - L13 were not covered by tests
headers: {
"Content-Type": "image/vnd.microsoft.icon",
"Cache-Control": "public, max-age=86400",
},
});
96 changes: 33 additions & 63 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading