feat: add semantic CSS stylesheets (#3274)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
Amruth Pillai
2026-07-30 12:39:15 +02:00
committed by GitHub
co-authored by Cursor Agent
parent 4ac19f81b3
commit d2ffbf9618
320 changed files with 78393 additions and 2915 deletions
@@ -0,0 +1,27 @@
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, it } from "vitest";
import { generateOpenApiDocumentation } from "./generate-spec";
const temporaryDirectories: string[] = [];
const committedSpec = new URL("../../../../docs/spec.json", import.meta.url);
afterEach(async () => {
await Promise.all(temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })));
});
it("keeps the committed OpenAPI specification synchronized without rewriting it", async () => {
const directory = await mkdtemp(join(tmpdir(), "openapi-documentation-"));
temporaryDirectories.push(directory);
const firstTarget = join(directory, "first.json");
const secondTarget = join(directory, "second.json");
const before = await readFile(committedSpec, "utf8");
await generateOpenApiDocumentation(firstTarget);
await generateOpenApiDocumentation(secondTarget);
expect(await readFile(firstTarget, "utf8")).toBe(before);
expect(await readFile(secondTarget, "utf8")).toBe(before);
expect(await readFile(committedSpec, "utf8")).toBe(before);
});
+20
View File
@@ -0,0 +1,20 @@
import { readFile, writeFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
export async function generateOpenApiDocumentation(
target = fileURLToPath(new URL("../../../../docs/spec.json", import.meta.url)),
) {
const packageJson = JSON.parse(await readFile(new URL("../../../../package.json", import.meta.url), "utf8")) as {
version: string;
};
process.env.APP_URL ??= "https://rxresu.me";
process.env.DATABASE_URL ??= "postgresql://localhost/reactive_resume_docs";
process.env.AUTH_SECRET ??= "documentation-generation-isolated-process-only";
const { generateOpenApiSpec } = await import("./generator");
const spec = await generateOpenApiSpec({ appUrl: "https://rxresu.me", version: packageJson.version });
await writeFile(target, `${JSON.stringify(spec, null, "\t")}\n`);
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
await generateOpenApiDocumentation(process.argv[2]);
}
+147
View File
@@ -0,0 +1,147 @@
import { describe, expect, it } from "vitest";
import z from "zod";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
import { createResumeDataJsonSchema } from "@reactive-resume/schema/resume/json-schema";
type GeneratedSpecView = {
components?: { schemas?: Record<string, unknown> };
paths?: Record<
string,
Record<
string,
{
requestBody?: {
content?: Record<string, { schema?: unknown }>;
};
}
>
>;
};
async function generateSpec() {
process.env.APP_URL ??= "https://rxresu.me";
process.env.DATABASE_URL ??= "postgresql://localhost/reactive_resume_test";
process.env.AUTH_SECRET ??= "openapi-generator-test-process-only";
const { generateOpenApiSpec } = await import("./generator");
return generateOpenApiSpec({
appUrl: "https://rxresu.me",
version: "9.8.7",
});
}
function getRequestSchema(spec: GeneratedSpecView, path: string, method: string) {
return spec.paths?.[path]?.[method]?.requestBody?.content?.["application/json"]?.schema;
}
function containsImpossibleSchema(value: unknown): boolean {
if (Array.isArray(value)) return value.some(containsImpossibleSchema);
if (typeof value !== "object" || value === null) return false;
const object = value as Record<string, unknown>;
const negated = object.not;
if (typeof negated === "object" && negated !== null && Object.keys(negated).length === 0) {
return true;
}
return Object.values(object).some(containsImpossibleSchema);
}
function findImpossibleRequestSchemas(spec: GeneratedSpecView) {
const impossibleRequests: string[] = [];
for (const [path, operations] of Object.entries(spec.paths ?? {})) {
for (const [method, operation] of Object.entries(operations)) {
for (const [mediaType, content] of Object.entries(operation.requestBody?.content ?? {})) {
if (containsImpossibleSchema(content.schema)) {
impossibleRequests.push(`${method.toUpperCase()} ${path} (${mediaType})`);
}
}
}
}
return impossibleRequests;
}
describe("generateOpenApiSpec", () => {
it("uses caller-provided application URL and version", async () => {
const spec = await generateSpec();
expect(spec.info).toMatchObject({
title: "Reactive Resume",
version: "9.8.7",
});
expect(spec.servers).toEqual([{ url: "https://rxresu.me/api/openapi" }]);
expect(spec.externalDocs).toEqual({
url: "https://docs.rxresu.me",
description: "Reactive Resume Documentation",
});
}, 15_000);
it("uses the canonical input-side ResumeData schema in update requests", async () => {
const spec = (await generateSpec()) as GeneratedSpecView;
const { $schema: _dialect, ...canonicalInputSchema } = createResumeDataJsonSchema();
expect(spec.components?.schemas?.ResumeData).toEqual(canonicalInputSchema);
expect(getRequestSchema(spec, "/resumes/{id}", "put")).toMatchObject({
properties: {
data: { $ref: "#/components/schemas/ResumeData" },
},
});
});
it("publishes the custom-section type and item correlation", async () => {
const spec = (await generateSpec()) as GeneratedSpecView;
const schema = z.fromJSONSchema(spec.components?.schemas?.ResumeData as Parameters<typeof z.fromJSONSchema>[0]);
const mismatched = {
...defaultResumeData,
customSections: [
{
id: "custom-experience",
type: "experience",
title: "Experience",
icon: "",
columns: 1,
hidden: false,
keepTogether: false,
startOnNewPage: false,
items: [{ id: "summary-item", hidden: false, content: "<p>Not an experience item</p>" }],
},
],
};
expect(schema.safeParse(mismatched).success).toBe(false);
});
it("does not publish impossible request schemas", async () => {
const spec = (await generateSpec()) as GeneratedSpecView;
expect(findImpossibleRequestSchemas(spec)).toEqual([]);
});
it("checks every request body media type for impossible schemas", () => {
const spec: GeneratedSpecView = {
paths: {
"/documents": {
post: {
requestBody: {
content: {
"application/json": { schema: { type: "object" } },
"multipart/form-data": { schema: { not: {} } },
},
},
},
},
},
};
expect(findImpossibleRequestSchemas(spec)).toEqual(["POST /documents (multipart/form-data)"]);
});
it("documents imported data as an accepted ResumeData input", async () => {
const spec = (await generateSpec()) as GeneratedSpecView;
expect(getRequestSchema(spec, "/resumes/import", "post")).toEqual({
type: "object",
properties: {
data: { $ref: "#/components/schemas/ResumeData" },
},
required: ["data"],
});
});
});
+80
View File
@@ -0,0 +1,80 @@
import { OpenAPIGenerator } from "@orpc/openapi";
import { JSON_SCHEMA_INPUT_REGISTRY, ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
import { downloadResumePdfProcedure } from "@reactive-resume/api/features/resume/export";
import router from "@reactive-resume/api/routers";
import { resumeDataSchema } from "@reactive-resume/schema/resume/data";
import { createResumeDataJsonSchema } from "@reactive-resume/schema/resume/json-schema";
export const openAPIRouter = {
...router,
resume: {
...router.resume,
downloadPdf: downloadResumePdfProcedure,
},
};
const { $schema: _dialect, ...resumeDataInputSchema } = createResumeDataJsonSchema();
type ResumeDataInputJsonSchema = Parameters<typeof JSON_SCHEMA_INPUT_REGISTRY.add<typeof resumeDataSchema>>[1];
JSON_SCHEMA_INPUT_REGISTRY.add(resumeDataSchema, resumeDataInputSchema as unknown as ResumeDataInputJsonSchema);
const importResumeInputSchema = openAPIRouter.resume.import["~orpc"].inputSchema;
if (importResumeInputSchema) {
JSON_SCHEMA_INPUT_REGISTRY.add(importResumeInputSchema, {
type: "object",
properties: {
data: { $ref: "#/components/schemas/ResumeData" },
},
required: ["data"],
});
}
const openAPIGenerator = new OpenAPIGenerator({
schemaConverters: [
new ZodToJsonSchemaConverter({
interceptors: [
({ options, next }) => {
const [required, schema] = next();
const impossible =
Object.keys(schema).length === 1 &&
typeof schema.not === "object" &&
schema.not !== null &&
Object.keys(schema.not).length === 0;
return options.strategy === "input" && impossible ? [required, {}] : [required, schema];
},
],
}),
],
});
type GenerateOpenApiSpecOptions = {
appUrl: string;
version: string;
};
export async function generateOpenApiSpec({ appUrl, version }: GenerateOpenApiSpecOptions) {
return await openAPIGenerator.generate(openAPIRouter, {
info: {
title: "Reactive Resume",
version,
description: "Reactive Resume API",
license: { name: "MIT", url: "https://github.com/amruthpillai/reactive-resume/blob/main/LICENSE" },
contact: { name: "Amruth Pillai", email: "hello@amruthpillai.com", url: "https://amruthpillai.com" },
},
servers: [{ url: `${appUrl}/api/openapi` }],
externalDocs: { url: "https://docs.rxresu.me", description: "Reactive Resume Documentation" },
commonSchemas: {
ResumeData: { schema: resumeDataSchema, strategy: "input" },
},
components: {
securitySchemes: {
apiKey: {
type: "apiKey",
name: "x-api-key",
in: "header",
description: "The API key to authenticate requests.",
},
},
},
security: [{ apiKey: [] }],
filter: ({ contract }) => !contract["~orpc"].route.tags?.includes("Internal"),
});
}
+4 -46
View File
@@ -1,24 +1,13 @@
import { SmartCoercionPlugin } from "@orpc/json-schema";
import { OpenAPIGenerator } from "@orpc/openapi";
import { OpenAPIHandler } from "@orpc/openapi/fetch";
import { onError } from "@orpc/server";
import { BatchHandlerPlugin, RequestHeadersPlugin, StrictGetMethodPlugin } from "@orpc/server/plugins";
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
import { downloadResumePdfProcedure } from "@reactive-resume/api/features/resume/export";
import router from "@reactive-resume/api/routers";
import { env } from "@reactive-resume/env/server";
import { resumeDataSchema } from "@reactive-resume/schema/resume/data";
import { appVersion } from "../app-version";
import { mergeResponseHeaders } from "../http/headers";
import { getRequestLocale } from "../rpc/locale";
const openAPIRouter = {
...router,
resume: {
...router.resume,
downloadPdf: downloadResumePdfProcedure,
},
};
import { generateOpenApiSpec, openAPIRouter } from "./generator";
const openAPIHandler = new OpenAPIHandler(openAPIRouter, {
plugins: [
@@ -36,46 +25,15 @@ const openAPIHandler = new OpenAPIHandler(openAPIRouter, {
],
});
const openAPIGenerator = new OpenAPIGenerator({
schemaConverters: [new ZodToJsonSchemaConverter()],
});
export async function handleOpenApi(request: Request) {
export async function handleOpenApi(request: Request, trustedClient = "unknown") {
if (request.method === "GET" && (request.url.endsWith("/spec.json") || request.url.endsWith("/spec"))) {
const spec = await openAPIGenerator.generate(openAPIRouter, {
info: {
title: "Reactive Resume",
version: appVersion,
description: "Reactive Resume API",
license: { name: "MIT", url: "https://github.com/amruthpillai/reactive-resume/blob/main/LICENSE" },
contact: { name: "Amruth Pillai", email: "hello@amruthpillai.com", url: "https://amruthpillai.com" },
},
servers: [{ url: `${env.APP_URL}/api/openapi` }],
externalDocs: { url: "https://docs.rxresu.me", description: "Reactive Resume Documentation" },
commonSchemas: {
ResumeData: { schema: resumeDataSchema },
},
components: {
securitySchemes: {
apiKey: {
type: "apiKey",
name: "x-api-key",
in: "header",
description: "The API key to authenticate requests.",
},
},
},
security: [{ apiKey: [] }],
filter: ({ contract }) => !contract["~orpc"].route.tags?.includes("Internal"),
});
return Response.json(spec);
return Response.json(await generateOpenApiSpec({ appUrl: env.APP_URL, version: appVersion }));
}
const resHeaders = new Headers();
const { response } = await openAPIHandler.handle(request, {
prefix: "/api/openapi",
context: { locale: getRequestLocale(request), reqHeaders: request.headers, resHeaders },
context: { locale: getRequestLocale(request), reqHeaders: request.headers, resHeaders, trustedClient },
});
if (!response) return new Response("NOT_FOUND", { status: 404 });