supermemory/apps/docs/scripts/prepare-site.ts

82 lines
2.8 KiB
TypeScript

import { cp, mkdir, readdir, rm } from "node:fs/promises"
import { resolve } from "node:path"
import apiPaths from "./api-paths.json"
import { prepareSocialImages } from "./social-images"
const root = resolve(import.meta.dir, "..")
const publicDir = resolve(root, ".holocron-public")
await rm(publicDir, { recursive: true, force: true })
await mkdir(publicDir, { recursive: true })
for (const name of ["images", "icons", "logo", "videos"]) {
await cp(resolve(root, name), resolve(publicDir, name), { recursive: true })
}
for (const name of await readdir(root)) {
if (name.startsWith("favicon") && name.endsWith(".png")) {
await cp(resolve(root, name), resolve(publicDir, name))
}
}
const response = await fetch("https://api.supermemory.ai/v4/openapi", {
signal: AbortSignal.timeout(30_000),
})
if (!response.ok) throw new Error(`OpenAPI download failed: ${response.status}`)
const spec = (await response.json()) as {
paths: Record<string, Record<string, Record<string, unknown>>>
components: { schemas: Record<string, Record<string, unknown>> }
}
if (!spec.paths || !Object.keys(spec.paths).length) {
throw new Error("OpenAPI specification has no paths")
}
for (const [operation, href] of Object.entries(apiPaths)) {
const [method, path] = operation.split(" ")
const definition = spec.paths[path]?.[method.toLowerCase()]
if (!definition) throw new Error(`Missing documented operation: ${operation}`)
definition["x-holocron"] = { href }
}
await Bun.write(resolve(publicDir, "openapi.json"), JSON.stringify(spec))
await prepareSocialImages(root, spec)
function expandSchemaReferences(
value: unknown,
references: string[] = [],
): unknown {
if (Array.isArray(value))
return value.map((item) => expandSchemaReferences(item, references))
if (value === null || typeof value !== "object") return value
const object = value as Record<string, unknown>
if (
typeof object.$ref === "string" &&
object.$ref.startsWith("#/components/schemas/")
) {
const name = object.$ref.slice("#/components/schemas/".length)
const schema = spec.components.schemas[name]
if (!schema) throw new Error(`Unknown schema reference: ${object.$ref}`)
if (references.includes(name)) {
return {
type: "object",
title: name,
description: `Recursive ${name}: accepts nested instances of the same schema. See the filtering guide for nested AND/OR examples. The complete recursive schema is available in /docs/openapi.json.`,
}
}
return expandSchemaReferences(
{
...schema,
...Object.fromEntries(
Object.entries(object).filter(([key]) => key !== "$ref"),
),
},
[...references, name],
)
}
return Object.fromEntries(
Object.entries(object).map(([key, item]) => [
key,
expandSchemaReferences(item, references),
]),
)
}
await Bun.write(
resolve(root, ".holocron-openapi.json"),
JSON.stringify(expandSchemaReferences(spec)),
)